home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / oleo_src.lha / src / ref.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-18  |  57.8 KB  |  2,547 lines

  1. /*    Copyright (C) 1990 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 1, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "funcdef.h"
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <signal.h>
  24.  
  25. #include "sysdef.h"
  26.  
  27. #include "global.h"
  28. #include "cell.h"
  29. #include "eval.h"
  30.  
  31. #ifdef REVERSE
  32. #define MIN_R MIN_COL
  33. #define MAX_R MAX_COL
  34. #define MIN_C MIN_ROW
  35. #define MAX_C MAX_ROW
  36. #else
  37. #define MIN_R MIN_ROW
  38. #define MAX_R MAX_ROW
  39. #define MIN_C MIN_COL
  40. #define MAX_C MAX_COL
  41. #endif
  42.  
  43. extern VOIDSTAR hash_new();
  44. extern VOIDSTAR hash_find();
  45. extern char *hash_insert();
  46. extern void hash_die();
  47. extern char *hash_apply();
  48.  
  49. extern VOIDSTAR init_stack EXT0();
  50. extern VOIDSTAR pop_stack EXT1(VOIDSTAR);
  51. extern void push_stack EXT2(VOIDSTAR, VOIDSTAR);
  52. extern void flush_stack EXT1(VOIDSTAR);
  53.  
  54. extern char *range_name EXT1(struct rng *);
  55.  
  56. extern unsigned char *parse_and_compile EXT1(char *);
  57. extern void byte_free EXT1(unsigned char *);
  58. extern int is_constant EXT1(unsigned char *);
  59.  
  60. extern unsigned char parse_cell_or_range EXT2(char **,struct rng *);
  61.  
  62. extern void pr_cell EXT3(CELLREF, CELLREF, CELL *);
  63.  
  64. extern char *cell_name EXT2(CELLREF, CELLREF);
  65. extern void update_cell EXT1(CELL *);
  66.  
  67. extern CELLREF cur_row;
  68. extern CELLREF cur_col;
  69. extern unsigned short current_cycle;
  70.  
  71. void add_range_ref EXT1(struct rng *);
  72. struct var *find_or_make_var EXT2(char *,int);
  73. void push_refs EXT1(struct ref_fm *);
  74. void flush_old_value EXT0();
  75.  
  76. void push_cell EXT2(CELLREF, CELLREF);
  77.  
  78. static void add_ref_fm EXT3(struct ref_fm **, CELLREF, CELLREF);
  79. static void flush_ref_fm EXT3(struct ref_fm **, CELLREF, CELLREF);
  80. static void flush_range_ref EXT3(struct rng *, CELLREF, CELLREF);
  81. void add_ref_to EXT1(int);
  82. #ifdef SPLIT_REFS
  83.  
  84. /* These two are tunable paramaters */
  85.  
  86. #define REF_START    3
  87. #define REF_INC        *=2
  88.  
  89. #else
  90. static void flush_ref_to EXT1(struct ref_to **);
  91. static void flush_fm_ref EXT1(struct ref_fm *);
  92. #endif
  93.  
  94. /* More tunable paramaters */
  95.  
  96. #define FIFO_START    40
  97. #define FIFO_INC    *=2
  98.  
  99. #define TO_MAGIC(row,col)    (((long)(row)<<BITS_PER_CELLREF)|(col))
  100. #define MAGIC_ROW(magic)    (((magic)>>BITS_PER_CELLREF)&CELLREF_MASK)
  101. #define MAGIC_COL(magic)    ((magic)&CELLREF_MASK)
  102.  
  103. #define BETWEEN(mid,lo,hi)    ((mid>=lo)&&(mid<=hi))
  104.  
  105. static VOIDSTAR moving;
  106.  
  107. /* These three for async cell updating */
  108. extern unsigned signal_ticks;
  109.  
  110. int timer_active = 0;
  111. struct ref_fm *timer_cells;
  112.  
  113. CELL *my_cell;
  114.  
  115. #ifdef TEST
  116. extern int debug;
  117. #endif
  118.  
  119. /* Functions for dealing exclusively with variables */
  120. VOIDSTAR the_vars;
  121.  
  122. struct value {
  123.     int    type;
  124.     union vals c_z;
  125. };
  126.  
  127. /* For the fifo-buffer */
  128. struct pos {
  129.     CELLREF row;
  130.     CELLREF col;
  131. };
  132.  
  133. struct cell_buf {
  134.     unsigned int size;
  135.     struct pos *buf;
  136.     struct pos *push_to_here;
  137.     struct pos *pop_frm_here;
  138. };
  139.  
  140.  
  141. /* Set the cell ROW,COL to STRING, parsing string as needed */
  142. void
  143. set_cell FUN3(CELLREF, row, CELLREF, col, char *, string)
  144. {
  145.     unsigned char *ret;
  146.  
  147.     cur_row=row;
  148.     cur_col=col;
  149.  
  150. #ifdef TEST
  151.     if(!string) {
  152.         error_msg("Null string to set_cell %s",cell_name(row,col));
  153.         return;
  154.     }
  155. #endif
  156.     while(*string==' ')
  157.         string++;
  158.  
  159.     if(!*string) {
  160.         my_cell=find_cell(cur_row,cur_col);
  161.         if(!my_cell)
  162.             return;
  163.         flush_old_value();
  164.         return;
  165.     }
  166.  
  167.     my_cell=find_or_make_cell(cur_row,cur_col);
  168.     flush_old_value();
  169.  
  170.     ret=parse_and_compile(string);
  171.     my_cell->cell_formula=ret;
  172. }
  173.  
  174. /* new_value() calls set_cell, but refuses to change locked cells, and
  175.    updates and prints the results.  It returns an error msg on error. . .
  176.  */
  177. char *
  178. new_value FUN3(CELLREF, row, CELLREF, col, char *, string)
  179. {
  180.     CELL *cp;
  181.     extern int default_lock;
  182.  
  183.     cp=find_cell(row,col);
  184.     if(((!cp || GET_LCK(cp)==LCK_DEF) && default_lock==LCK_LCK) || (cp && GET_LCK(cp)==LCK_LCK)) {
  185.         return "cell is locked";
  186.     }
  187.  
  188.     set_cell(row, col, string);
  189.     if(my_cell) {
  190.         update_cell(my_cell);
  191.         if(is_constant(my_cell->cell_formula)) {
  192.             byte_free(my_cell->cell_formula);
  193.             my_cell->cell_formula=0;
  194.         }
  195.         pr_cell(row,col,my_cell);
  196.         my_cell=0;
  197.     }
  198.     return 0;
  199. }
  200.  
  201. /* This sets the cell to a constant, stored in VALUE, whose type is in TYPE */
  202. char *
  203. set_new_value FUN4(CELLREF,row, CELLREF,col, int,type, union vals *,value)
  204. {
  205.     CELL *cp;
  206.     extern int default_lock;
  207.  
  208.     if(type==TYP_ERR)
  209.         type=0;
  210.     cur_row=row;
  211.     cur_col=col;
  212.     if(type==0) {
  213.         cp=find_cell(row,col);
  214.         if(cp && GET_TYP(cp)) {
  215.             if((GET_LCK(cp)==LCK_DEF && default_lock==LCK_LCK) || GET_LCK(cp)==LCK_LCK)
  216.                 return "cell is locked";
  217.             my_cell=cp;
  218.             flush_old_value();
  219.             SET_TYP(cp,0);
  220.         }
  221.         my_cell=0;
  222.         return 0;
  223.     } else {
  224.         cp=find_or_make_cell(row,col);
  225.         if((GET_LCK(cp)==LCK_DEF && default_lock==LCK_LCK) || GET_LCK(cp)==LCK_LCK)
  226.             return "cell is locked";
  227.         my_cell=cp;
  228.         flush_old_value();
  229.         SET_TYP(cp,type);
  230.         /* cp->c_z= *value; */
  231.         switch(type) {
  232.         case TYP_FLT:
  233.             cp->cell_flt=value->c_d;
  234.             cp->cell_formula=0;
  235.             break;
  236.  
  237.         case TYP_INT:
  238.             cp->cell_int=value->c_l;
  239.             cp->cell_formula=0;
  240.             break;
  241.  
  242.         case TYP_STR:
  243.             cp->cell_str=strdup(value->c_s);
  244.             cp->cell_formula=0;
  245.             break;
  246.  
  247.         case TYP_BOL:
  248.             cp->cell_bol=value->c_i;
  249.             cp->cell_formula=0;
  250.             break;
  251.  
  252.         case TYP_ERR:
  253.             cp->cell_err=value->c_i;
  254.             cp->cell_formula=0;
  255.             break;
  256. #ifdef TEST
  257.         default:
  258.             panic("Unknown type %d in set_new_value",GET_TYP(cp));
  259. #endif
  260.         }
  261.     }
  262.     push_refs(cp->cell_refs_from);
  263.     pr_cell(row,col,cp);
  264.     my_cell=0;
  265.     return 0;
  266. }
  267.  
  268. /* We're reading in a cell, whose formula is FORM, and whose current value
  269.    is VAL.  Parse both of them. . .  (Parsing of VAL is quite primitive)
  270.  */
  271. char *
  272. read_new_value FUN4(CELLREF, row, CELLREF, col, char *, form, char *,val)
  273. {
  274.     unsigned char *new_bytes;
  275.     extern double __plinf,__neinf,__nan;
  276.  
  277.     cur_row=row;
  278.     cur_col=col;
  279.     my_cell=find_or_make_cell(cur_row, cur_col);
  280.     flush_old_value();
  281.     SET_TYP(my_cell,0);
  282.  
  283.     if(form) {
  284.         new_bytes=parse_and_compile(form);
  285.         my_cell->cell_formula=new_bytes;
  286.     }
  287.  
  288.     if(val) {
  289.         if(val[0]=='"') {
  290.             char *sp,*nsp;
  291.  
  292.             sp=val+1;
  293.             SET_TYP(my_cell,TYP_STR);
  294.             while(*sp)
  295.                 sp++;
  296.             if(*--sp!='"') {
  297.                 if(*sp=='\r' && sp[-1]=='"')
  298.                     --sp;
  299.                 else
  300.                     panic("Can't find \" in read_new value");
  301.             }
  302.             *sp='\0';
  303.             nsp=my_cell->cell_str=ck_malloc(sp-val);
  304.             for(sp=val+1;*sp;)
  305.                 *nsp++= *sp++;
  306.             *nsp++='\0';
  307.         } else if(isdigit(val[0]) || val[0]=='.' || val[0]=='-' || val[0]=='+') {
  308.             char *v;
  309.  
  310.             v=val;
  311.             SET_TYP(my_cell,TYP_INT);
  312.             my_cell->cell_int=astol(&v);
  313.             if(*v) {
  314.                 SET_TYP(my_cell,TYP_FLT);
  315.                 v=val;
  316.                 my_cell->cell_flt=astof(&v);
  317.                 if(*v)
  318.                     return "unknown number";
  319.             }
  320.         } else if(val[0]=='#') {
  321.             char **en;
  322.             extern int stricmp();
  323.  
  324.             if(!stricmp(tname,val)) {
  325.                 SET_TYP(my_cell,TYP_BOL);
  326.                 my_cell->cell_bol=1;
  327.             } else if(!stricmp(fname,val)) {
  328.                 SET_TYP(my_cell,TYP_BOL);
  329.                 my_cell->cell_bol=0;
  330.             } else if(!stricmp(iname,val)) {
  331.                 SET_TYP(my_cell,TYP_FLT);
  332.                 my_cell->cell_flt=__plinf;
  333.             } else if(!stricmp(iname,val)) {
  334.                 SET_TYP(my_cell,TYP_FLT);
  335.                 my_cell->cell_flt=__plinf;
  336.             } else if(!stricmp(mname,val)) {
  337.                 SET_TYP(my_cell,TYP_FLT);
  338.                 my_cell->cell_flt=__neinf;
  339.             } else if(!stricmp(nname,val)) {
  340.                 SET_TYP(my_cell,TYP_FLT);
  341.                 my_cell->cell_flt=__nan;
  342.             } else {
  343.                 SET_TYP(my_cell,TYP_ERR);
  344.                 for(en=ename;*en;en++)
  345.                     if(!stricmp(*en,val))
  346.                         break;
  347.                 if(*en)
  348.                     my_cell->cell_err=en- &ename[0];
  349.                 else
  350.                     my_cell->cell_err=1;
  351.             }
  352.         } else
  353.             panic("What is a '%s'?",val);
  354.     }
  355.  
  356.     my_cell=0;
  357.     return 0;
  358. }
  359.  
  360. /* This moves the contents, format, etc from RF,CF to RT,CT  RF or RT may be
  361.    NON_ROW, in which case the cell's contents are moved to/from a static
  362.    storage area.  Moving anything from NON_ROW before moving anything into it
  363.    or moving two things at a time into NON_ROW are both bad ideas. . .
  364.  
  365.    Also note that move_cell does not call move_outside, which may or may not
  366.    be a bug. . .  Move_cell is only called as part of sorting, which is why 
  367.    we may *not* want to call move_outside. . .
  368.  */
  369.  
  370. void
  371. move_cell FUN4(CELLREF,rf, CELLREF,cf, CELLREF,rt, CELLREF,ct)
  372. {
  373.     CELL *cpf;
  374.  
  375.     static CELLREF non_rf,non_cf;
  376.     static struct cell non_cell;
  377.  
  378.     extern void shift_formula();
  379.  
  380.     if(rf==NON_ROW) {
  381.         cur_row=rt;
  382.         cur_col=ct;
  383.         my_cell=find_cell(cur_row,cur_col);
  384.         if(my_cell)
  385.             flush_old_value();
  386.         else if(!non_cell.cell_flags && !non_cell.cell_formula)
  387.             return;
  388.         else
  389.             my_cell=find_or_make_cell(cur_row,cur_col);
  390.  
  391.         my_cell->cell_flags=non_cell.cell_flags;
  392.         my_cell->cell_refs_to=non_cell.cell_refs_to;
  393.         my_cell->cell_formula=non_cell.cell_formula;
  394.         my_cell->cell_cycle=non_cell.cell_cycle;
  395.         my_cell->c_z=non_cell.c_z;
  396.         push_refs(my_cell->cell_refs_from);
  397.         if(my_cell->cell_refs_to)
  398.             shift_formula(rt-non_rf,ct-non_cf);
  399.         my_cell=0;
  400.         return;
  401.     }
  402.  
  403.     cpf=find_cell(rf,cf);
  404.  
  405.     if(rt==NON_ROW) {
  406.         non_rf=rf;
  407.         non_cf=cf;
  408.         if(!cpf)
  409.             bzero(&non_cell,sizeof(non_cell));
  410.         else {
  411.             non_cell.cell_flags=cpf->cell_flags;
  412.             non_cell.cell_refs_to=cpf->cell_refs_to;
  413.             non_cell.cell_formula=cpf->cell_formula;
  414.             non_cell.cell_cycle=cpf->cell_cycle;
  415.             non_cell.c_z=cpf->c_z;
  416.             cpf->cell_flags=0;
  417.             cpf->cell_refs_to=0;
  418.             cpf->cell_formula=0;
  419.             cpf->cell_cycle=0;
  420.         }
  421.         return;
  422.     }
  423.  
  424.     cur_row=rt;
  425.     cur_col=ct;
  426.     my_cell=find_cell(cur_row,cur_col);
  427.     if((!cpf || (!cpf->cell_flags && !cpf->cell_formula)) && !my_cell)
  428.         return;
  429.     if(!my_cell) {
  430.         my_cell=find_or_make_cell(cur_row,cur_col);
  431.         cpf=find_cell(rf,cf);    /* FOO */
  432.     } else
  433.         flush_old_value();
  434.  
  435.     if(!cpf)
  436.         return;
  437.  
  438.     my_cell->cell_flags=cpf->cell_flags;
  439.     my_cell->cell_refs_to=cpf->cell_refs_to;
  440.     my_cell->cell_formula=cpf->cell_formula;
  441.     my_cell->cell_cycle=cpf->cell_cycle;
  442.     my_cell->c_z=cpf->c_z;
  443.  
  444.     cpf->cell_flags=0;
  445.     cpf->cell_refs_to=0;
  446.     cpf->cell_formula=0;
  447.     cpf->cell_cycle=0;
  448.  
  449.     push_refs(my_cell->cell_refs_from);
  450.     if(my_cell->cell_refs_to)
  451.         shift_formula(rt-rf,ct-cf);
  452.     my_cell=0;
  453. }
  454.  
  455. void
  456. copy_cell FUN4(CELLREF,rf, CELLREF,cf, CELLREF,rt, CELLREF,ct)
  457. {
  458.     CELL *cpf;
  459.  
  460.     cpf=find_cell(rf,cf);
  461.     cur_row=rt;
  462.     cur_col=ct;
  463.     my_cell=find_cell(cur_row,cur_col);
  464.     if((!cpf || (!cpf->cell_flags && !cpf->cell_formula)) && !my_cell)
  465.         return;
  466.     if(!my_cell) {
  467.         my_cell=find_or_make_cell(cur_row,cur_col);
  468.         cpf=find_cell(rf,cf);    /* FOO */
  469.     } else
  470.         flush_old_value();
  471.  
  472.     if(!cpf)
  473.         return;
  474.  
  475.     my_cell->cell_flags=cpf->cell_flags;
  476.     my_cell->cell_cycle=cpf->cell_cycle;
  477.  
  478. #ifdef SPLIT_REFS
  479.     if(cpf->cell_refs_to {
  480.         size_t siz;
  481.  
  482.  
  483.         siz=sizeof(struct ref_to)+(cpf->cell_refs_to->refs_alloc-1)*sizeof(unsigned char);
  484.         my_cell->cell_refs_to=ck_malloc(siz);
  485.         bcopy(cpf->cell_refs_to,my_cell->cell_refs_to,siz);
  486.     } else
  487.         my_cell->cell_refs_to=0;
  488. #else
  489.     my_cell->cell_refs_to=cpf->cell_refs_to;
  490.     if(my_cell->cell_refs_to)
  491.         my_cell->cell_refs_to->refs_refcnt++;
  492. #endif
  493.  
  494.     if(GET_TYP(my_cell)==TYP_STR)
  495.         my_cell->cell_str=strdup(cpf->cell_str);
  496.     else
  497.         my_cell->c_z=cpf->c_z;
  498.  
  499.     if(cpf->cell_formula) {
  500.         unsigned char *fp;
  501.         unsigned char *hi;
  502.         unsigned char byte;
  503.         CELLREF trr,tcc;
  504.         struct rng trng;
  505.         struct function *f;
  506.         size_t len;
  507.         struct var *v;
  508.         CELL *tcp;
  509.  
  510.         fp=cpf->cell_formula;
  511.         hi=0;
  512.         if(!moving)
  513.             moving=init_stack();
  514.         while((byte= *fp++)!=ENDCOMP) {
  515.             if(byte<USR1)
  516.                 f= &the_funs[byte];
  517.             else if(byte<SKIP) {
  518.                 int tmp;
  519. #ifdef TEST
  520.                 extern int n_usr_funs;
  521.  
  522.                 if(byte-USR1>=n_usr_funs)
  523.                     panic("Only have %d usr-function slots, but found byte for slot %d",n_usr_funs,1+byte-USR1);
  524. #endif
  525.                 tmp= *fp++;
  526.                 f= &usr_funs[byte-USR1][tmp];
  527.             } else
  528.                 f= &skip_funs[byte-SKIP];
  529.  
  530.             if(f->fn_argn&X_J)
  531.                 fp++;
  532.             else if(f->fn_argn&X_JL)
  533.                 fp+=2;
  534.  
  535.             if((f->fn_argn&X_ARGS)==X_AN)
  536.                 fp++;
  537.  
  538.             switch(byte) {
  539.             case CONST_FLT:
  540.                 fp+=sizeof(double);
  541.                 break;
  542.  
  543.             case CONST_INT:
  544.                 fp+=sizeof(long);
  545.                 break;
  546.  
  547.             case CONST_STR:
  548.                 if(!hi)
  549.                     hi=fp+fp[-1];
  550.                 break;
  551.  
  552.             case CONST_STR_L:
  553.                 if(!hi)
  554.                     hi=fp+fp[-2]+((unsigned)(fp[-1])<<8);
  555.                 break;
  556.  
  557.             case CONST_ERR:
  558.                 fp+=1/* +sizeof(char *) */;
  559.                 break;
  560.  
  561.             case VAR:
  562.                 bcopy(fp,&v,sizeof(struct var *));
  563.                 fp+=sizeof(struct var *);
  564.                 add_ref_fm(&(v->var_ref_fm),cur_row,cur_col);
  565.                 switch(v->var_flags) {
  566.                 case VAR_UNDEF:
  567.                     break;
  568.                 case VAR_CELL:
  569.                     tcp=find_cell(v->v_rng.lr,v->v_rng.lc);
  570.                     add_ref_fm(&(tcp->cell_refs_from),cur_row,cur_col);
  571.                     break;
  572.                 case VAR_RANGE:
  573.                     add_range_ref(&(v->v_rng));
  574.                     break;
  575.                 }
  576.                 break;
  577.  
  578.             case R_CELL:
  579.             case R_CELL|COLREL:
  580.             case R_CELL|ROWREL:
  581.             case R_CELL|ROWREL|COLREL:
  582.                 push_stack(moving,fp);
  583.                 fp+=EXP_ADD;
  584.                 break;
  585.  
  586.             case RANGE:
  587.             case RANGE|LRREL:
  588.             case RANGE|LRREL|LCREL:
  589.             case RANGE|LRREL|LCREL|HCREL:
  590.             case RANGE|LRREL|HCREL:
  591.             case RANGE|LRREL|HRREL:
  592.             case RANGE|LRREL|HRREL|LCREL:
  593.             case RANGE|LRREL|HRREL|LCREL|HCREL:
  594.             case RANGE|LRREL|HRREL|HCREL:
  595.             case RANGE|HRREL:
  596.             case RANGE|HRREL|LCREL:
  597.             case RANGE|HRREL|LCREL|HCREL:
  598.             case RANGE|HRREL|HCREL:
  599.             case RANGE|LCREL:
  600.             case RANGE|LCREL|HCREL:
  601.             case RANGE|HCREL:
  602.                 push_stack(moving,fp);
  603.                 fp+=EXP_ADD_RNG;
  604.                 break;
  605.  
  606.             default:
  607.                 break;
  608.             }
  609.         }
  610.         if(!hi)
  611.             hi=fp;
  612.         else
  613.             hi+=strlen((char *)hi);
  614.         hi++;
  615.         len=hi-cpf->cell_formula;
  616.         my_cell->cell_formula=cpf->cell_formula;
  617.         cpf->cell_formula=ck_malloc(hi-cpf->cell_formula);
  618.         bcopy(my_cell->cell_formula,cpf->cell_formula,len);
  619.         while(fp=pop_stack(moving)) {
  620.             byte= fp[-1];
  621.             if((byte|ROWREL|COLREL)==(R_CELL|ROWREL|COLREL)) {
  622.                 trr=GET_ROW(fp);
  623.                 tcc=GET_COL(fp);
  624. /*                if((*fp)&ROWREL) {
  625.                     trr+=rt-rf;
  626.                     PUT_ROW(fp,trr);
  627.                 }  pass travis*/
  628.                 if(byte&ROWREL) {
  629.                     trr+=rt-rf;
  630.                     PUT_ROW(fp,trr);
  631.                 }
  632.                 if(byte&COLREL) {
  633.                     tcc+=ct-cf;
  634.                     PUT_COL(fp,tcc);
  635.                 }
  636.                 tcp=find_or_make_cell(trr,tcc);
  637.                 add_ref_fm(&(tcp->cell_refs_from),cur_row,cur_col);
  638.             }
  639. #ifdef TEST
  640.             else if((byte|LRREL|HRREL|LCREL|HCREL)!=
  641.                 (RANGE|LRREL|HRREL|LCREL|HCREL))
  642.                 panic("Unknown byte %x in copy_cell",byte);
  643. #endif
  644.             else {
  645.                 GET_RNG(fp,&trng);
  646.                 if(byte&LRREL)
  647.                     trng.lr+=rt-rf;
  648.                 if(byte&HRREL)
  649.                     trng.hr+=rt-rf;
  650.                 if(byte&LCREL)
  651.                     trng.lc+=ct-cf;
  652.                 if(byte&HCREL)
  653.                     trng.hc+=ct-cf;
  654.                 PUT_RNG(fp,&trng);
  655.                 add_range_ref(&trng);
  656.             }
  657.         }
  658.         update_cell(my_cell);
  659.     } else {
  660.         my_cell->cell_formula=0;
  661.     }
  662.     pr_cell(cur_row,cur_col,my_cell);
  663.  
  664.     push_refs(my_cell->cell_refs_from);
  665.     my_cell=0;
  666. }
  667.  
  668. /* Take away the value of CP.  This means getting rid of all the references
  669.    to it, etc.
  670.  */
  671. void
  672. flush_old_value FUN0()
  673. {
  674.     struct ref_to *ref;
  675.     unsigned char *refloc;
  676.     int n;
  677.     unsigned char byte;
  678.     CELL *other_cell;
  679.     struct var *varp;
  680.  
  681.     ref=my_cell->cell_refs_to;
  682.     if(ref) {
  683.         for(n=0;n<ref->refs_used;n++) {
  684.             /* Switch on formula[ref->to_refs[n]] */
  685.             refloc= &(my_cell->cell_formula[ref->to_refs[n]]);
  686.             byte= refloc[0];
  687.             switch (byte) {
  688.             case F_ROW:
  689.             case F_COL:
  690.                 break;
  691.  
  692.             case R_CELL:
  693.             case R_CELL|ROWREL:
  694.             case R_CELL|COLREL:
  695.             case R_CELL|ROWREL|COLREL:
  696.                 other_cell=find_cell(GET_ROW(refloc+1), GET_COL(refloc+1));
  697.                 if(other_cell)
  698.                     flush_ref_fm(&(other_cell->cell_refs_from), cur_row, cur_col);
  699. #ifdef TEST
  700.                 else
  701.                     error_msg("Can't find other_cell in flush_old_value");
  702. #endif
  703.                 break;
  704.             case RANGE:
  705.             case RANGE|LRREL:
  706.             case RANGE|LRREL|LCREL:
  707.             case RANGE|LRREL|LCREL|HCREL:
  708.             case RANGE|LRREL|HCREL:
  709.             case RANGE|LRREL|HRREL:
  710.             case RANGE|LRREL|HRREL|LCREL:
  711.             case RANGE|LRREL|HRREL|LCREL|HCREL:
  712.             case RANGE|LRREL|HRREL|HCREL:
  713.             case RANGE|HRREL:
  714.             case RANGE|HRREL|LCREL:
  715.             case RANGE|HRREL|LCREL|HCREL:
  716.             case RANGE|HRREL|HCREL:
  717.             case RANGE|LCREL:
  718.             case RANGE|LCREL|HCREL:
  719.             case RANGE|HCREL:
  720.                 {
  721.                     struct rng rng;
  722.  
  723.                     GET_RNG(refloc+1,&rng);
  724.                     flush_range_ref(&rng,cur_row,cur_col);
  725.                 }
  726.                 break;
  727.  
  728.             case VAR:
  729.                 bcopy(&refloc[1],&varp,sizeof(struct var *));
  730.                 flush_ref_fm(&(varp->var_ref_fm),cur_row,cur_col);
  731.                 if(varp->var_flags==VAR_CELL) {
  732.                     other_cell=find_cell(varp->v_rng.lr,varp->v_rng.lc);
  733.                     if(other_cell)
  734.                         flush_ref_fm(&(other_cell->cell_refs_from),cur_row,cur_col);
  735.                 } else if(varp->var_flags==VAR_RANGE)
  736.                     flush_range_ref(&(varp->v_rng),cur_row,cur_col);
  737. #ifdef TEST
  738.                 else if(varp->var_flags!=VAR_UNDEF)
  739.                     panic("Unknown var type %d",varp->var_flags);
  740. #endif
  741.                 break;
  742.  
  743.             default:
  744.             {
  745.                 struct function *fun;
  746.  
  747.                 if(byte<USR1)
  748.                     fun= &the_funs[byte];
  749. #ifdef TEST
  750.                 else if(byte>=SKIP)
  751.                     fun=0,panic("SKIP? in flush_old_value()");
  752. #endif
  753.                 else
  754.                     fun= &usr_funs[byte][refloc[1]];
  755.  
  756.                 if(fun->fn_comptype&C_T) {
  757. #ifdef TEST
  758.                     if(!timer_cells || !timer_cells->refs_used)
  759.                         panic("No timer cells in flush_timer_cell");
  760. #endif
  761.                     flush_ref_fm(&timer_cells,cur_row,cur_col);
  762.                     if(!timer_cells || timer_cells->refs_used==0) {
  763.                         timer_active=0;
  764. #ifndef __TURBOC__
  765.                         ualarm(0,0);
  766. #endif
  767.                     }
  768.                     break;
  769.                 } else
  770.                     error_msg("Bad ref_to of %d.%x ignored",ref->to_refs[n],byte);
  771.             }
  772.                 break;
  773.             }
  774.         }
  775. #ifdef SPLIT_REFS
  776.         ref->refs_used=0;
  777. #else
  778.         flush_ref_to(&(my_cell->cell_refs_to));
  779. #endif
  780.     }
  781.     if(my_cell->cell_formula) {
  782.         byte_free(my_cell->cell_formula);
  783.         my_cell->cell_formula=0;
  784.     }
  785.     if(GET_TYP(my_cell)==TYP_STR)
  786.         free(my_cell->cell_str);
  787.     SET_TYP(my_cell,0);
  788. }
  789.  
  790. /* --------- Routines for dealing with cell references to other cells ------ */
  791.  
  792. void
  793. add_ref FUN2(CELLREF,row, CELLREF,col)
  794. {
  795.     CELL *other_cell;
  796.  
  797.     other_cell=find_or_make_cell(row,col);
  798.     add_ref_fm(&(other_cell->cell_refs_from), cur_row, cur_col);
  799. }
  800.  
  801. void
  802. add_range_ref FUN1(struct rng *,rng)
  803. {
  804.     CELL *other_cell;
  805. #ifndef SPLIT_REFS
  806.     struct ref_fm *oldref,*newref;
  807.     struct ref_fm nonref;
  808. #endif
  809.     /* This is horribly inefficient:  Simply referencing a cell makes
  810.        it appear.  On the other hand, there is no other easy way to deal
  811.        with the references to the cells (That I know of, anyway) */
  812.     make_cells_in_range(rng);
  813. #ifndef SPLIT_REFS
  814.     /* Be efficient:  If cells in the range currently have the same
  815.        references, they'll have the same references afterward, so just
  816.        adjust the refcounts */
  817.     nonref.refs_refcnt=1;
  818.     other_cell=next_cell_in_range();
  819.     oldref=other_cell->cell_refs_from;
  820.     if(oldref && oldref->refs_refcnt==1)
  821.         oldref= &nonref;
  822.  
  823.     add_ref_fm(&(other_cell->cell_refs_from), cur_row, cur_col);
  824.     newref=other_cell->cell_refs_from;
  825.     while(other_cell=next_cell_in_range()) {
  826.         if(other_cell->cell_refs_from==oldref) {
  827.             if(oldref) {
  828.                 if(oldref->refs_refcnt==1) {
  829.                     flush_fm_ref(oldref);
  830.                     oldref= &nonref;
  831.                 } else
  832.                     oldref->refs_refcnt--;
  833.             }
  834.             other_cell->cell_refs_from=newref;
  835.             newref->refs_refcnt++;
  836.         } else if(oldref== &nonref && (!other_cell->cell_refs_from || other_cell->cell_refs_from->refs_refcnt>1)) {
  837.             oldref=other_cell->cell_refs_from;
  838.             add_ref_fm(&(other_cell->cell_refs_from), cur_row, cur_col);
  839.             newref=other_cell->cell_refs_from;
  840.         } else
  841.             add_ref_fm(&(other_cell->cell_refs_from), cur_row, cur_col);
  842.     }
  843.     /* if(oldref && oldref->refs_refcnt==0) {
  844.         oldref->refs_refcnt=1;
  845.         flush_fm_ref(oldref);
  846.     } */
  847. #else
  848.     while(other_cell=next_cell_in_range())
  849.         add_ref_fm(&(other_cell->cell_refs_from), cur_row, cur_col);
  850. #endif
  851. }
  852.  
  853. static void
  854. flush_range_ref FUN3(struct rng *,rng, CELLREF,rr, CELLREF,cc)
  855. {
  856.     CELL *other_cell;
  857. #ifndef SPLIT_REFS
  858.     struct ref_fm *oldref,*newref;
  859.     struct ref_fm nonref;
  860. #endif
  861.     /* This is horribly inefficient:  Simply referencing a cell makes
  862.        it appear.  On the other hand, there is no other easy way to deal
  863.        with the references to the cells (That I know of, anyway) */
  864.     find_cells_in_range(rng);
  865. #ifndef SPLIT_REFS
  866.     /* Be efficient:  If cells in the range currently have the same
  867.        references, they'll have the same references afterward, so just
  868.        adjust the refcounts */
  869.     nonref.refs_refcnt=1;
  870.     other_cell=next_cell_in_range();
  871.     oldref=other_cell->cell_refs_from;
  872.     if(oldref && oldref->refs_refcnt==1)
  873.         oldref= &nonref;
  874.  
  875.     flush_ref_fm(&(other_cell->cell_refs_from), rr, cc);
  876.     newref=other_cell->cell_refs_from;
  877.     while(other_cell=next_cell_in_range()) {
  878.         if(other_cell->cell_refs_from==oldref) {
  879.             if(oldref) {
  880.                 if(oldref->refs_refcnt==1) {
  881.                     flush_fm_ref(oldref);
  882.                     oldref= &nonref;
  883.                 } else
  884.                     oldref->refs_refcnt--;
  885.             }
  886.             other_cell->cell_refs_from=newref;
  887.             if(newref)
  888.                 newref->refs_refcnt++;
  889.         } else if(oldref== &nonref && (!other_cell->cell_refs_from || other_cell->cell_refs_from->refs_refcnt>1)) {
  890.             oldref=other_cell->cell_refs_from;
  891.             flush_ref_fm(&(other_cell->cell_refs_from), rr, cc);
  892.             newref=other_cell->cell_refs_from;
  893.         } else
  894.             flush_ref_fm(&(other_cell->cell_refs_from), rr, cc);
  895.     }
  896. #else
  897.     while(other_cell=next_cell_in_range())
  898.         flush_ref_fm(&(other_cell->cell_refs_from), rr, cc);
  899. #endif
  900. }
  901.  
  902. /* SPLIT_REFS should probably go away, since it is a performance loss.
  903.    When it is defined, we allocate a a reference structure for each cell with
  904.    references, and update them individually.
  905.  
  906.    The default is to allocate one reference structure for each *different*
  907.    reference, and have multiple cells point to it.  We use reference counts
  908.    to keep track of when to delete the reference structure.  This would
  909.    appear to be a performance loss, but because of the increased efficiency
  910.    in referencing ranges, it may actually be faster.  It also uses *far* less
  911.    memory than SPLIT_REFS */
  912.  
  913.  
  914. #ifndef SPLIT_REFS
  915. #ifdef __TURBOC__
  916. #define FM_HASH_NUM 51
  917. #define TO_HASH_NUM 13
  918. #else
  919. #define FM_HASH_NUM 503
  920. #define TO_HASH_NUM 29
  921. #endif
  922. #ifdef TEST
  923. static int fm_misses = 0;
  924. static int to_misses = 0;
  925. #endif
  926.  
  927. static struct ref_fm *fm_list[FM_HASH_NUM];
  928. static struct ref_fm *fm_tmp_ref;
  929. static unsigned fm_tmp_ref_alloc;
  930.  
  931. static struct ref_to *to_list[TO_HASH_NUM];
  932. static struct ref_to *to_tmp_ref;
  933. static unsigned to_tmp_ref_alloc;
  934.  
  935. void
  936. flush_refs FUN0()
  937. {
  938.     int n;
  939.     struct ref_fm *ftmp,*oftmp;
  940.     struct ref_to *ttmp,*ottmp;
  941.  
  942.     for(n=0;n<FM_HASH_NUM;n++) {
  943.         for(ftmp=fm_list[n];ftmp;ftmp=oftmp) {
  944.             oftmp=ftmp->refs_next;
  945.             free(ftmp);
  946.         }
  947.         fm_list[n]=0;
  948.     }
  949.     for(n=0;n<TO_HASH_NUM;n++) {
  950.         for(ttmp=to_list[n];ttmp;ttmp=ottmp) {
  951.             ottmp=ttmp->refs_next;
  952.             free(ttmp);
  953.         }
  954.         to_list[n]=0;
  955.     }
  956. }
  957.  
  958. static struct ref_fm *
  959. find_fm_ref FUN0()
  960. {
  961.     struct ref_fm *tmp;
  962.     int n;
  963.     unsigned long hash;
  964.  
  965. #if 1
  966.     for(hash=0,n=0;n<fm_tmp_ref->refs_used;n++) {
  967.         hash+=(n+1) * (((fm_tmp_ref->fm_refs[n].ref_row)<<BITS_PER_CELLREF) + 
  968.                 fm_tmp_ref->fm_refs[n].ref_col);
  969.     }
  970.     hash%=FM_HASH_NUM;
  971. #else
  972.     hash=fm_tmp_ref->refs_used;
  973. #endif
  974.     for(tmp=fm_list[hash];tmp;tmp=tmp->refs_next) {
  975.         if(tmp->refs_used!=fm_tmp_ref->refs_used)
  976.             continue;
  977.         if(!bcmp(tmp->fm_refs,fm_tmp_ref->fm_refs,fm_tmp_ref->refs_used*sizeof(struct ref_array))) {
  978.             tmp->refs_refcnt++;
  979.             return tmp;
  980.         }
  981. #ifdef TEST
  982.         else
  983.             fm_misses++;
  984. #endif
  985.     }
  986.  
  987.     tmp=ck_malloc(sizeof(struct ref_fm)+(fm_tmp_ref->refs_used-1)*sizeof(struct ref_array));
  988.     tmp->refs_next=fm_list[hash];
  989.     fm_list[hash]=tmp;
  990.     tmp->refs_refcnt=1;
  991.     tmp->refs_used=fm_tmp_ref->refs_used;
  992.     bcopy(fm_tmp_ref->fm_refs,tmp->fm_refs,tmp->refs_used*sizeof(struct ref_array));
  993.  
  994.     return tmp;
  995. }
  996.  
  997. static void flush_fm_ref FUN1(struct ref_fm *,old)
  998. {
  999.     struct ref_fm *tmp;
  1000.     int n;
  1001.     unsigned long hash;
  1002.  
  1003.     --(old->refs_refcnt);
  1004.  
  1005. #ifdef DEFER_FREE
  1006.     return;
  1007. #endif
  1008.     if(!old->refs_refcnt) {
  1009. #if 1
  1010.         for(hash=0,n=0;n<old->refs_used;n++) {
  1011.             hash+=(n+1) * (((old->fm_refs[n].ref_row)<<BITS_PER_CELLREF) + 
  1012.                 old->fm_refs[n].ref_col);
  1013.         }
  1014.         hash%=FM_HASH_NUM;
  1015. #else
  1016.         hash=old->refs_used;
  1017. #endif
  1018.         if(fm_list[hash]==old)
  1019.             fm_list[hash]=old->refs_next;
  1020.         else {
  1021.             for(tmp=fm_list[hash];tmp && tmp->refs_next!=old;tmp=tmp->refs_next)
  1022.                 ;
  1023. #ifdef TEST
  1024.             if(!tmp) {
  1025.                 error_msg("Old not in refs_list in flush_fm_ref(%p)",old);
  1026.                 return;
  1027.             }
  1028. #endif
  1029.             tmp->refs_next=old->refs_next;
  1030.         }
  1031.         free(old);
  1032.     }
  1033. }
  1034.  
  1035. static void
  1036. add_ref_fm FUN3(struct ref_fm **, where, CELLREF, r, CELLREF, c)
  1037. {
  1038.     struct ref_fm *from;
  1039.     int n;
  1040.  
  1041.     from= *where;
  1042.     if(!from) {
  1043.         if(!fm_tmp_ref) {
  1044.             fm_tmp_ref=ck_malloc(sizeof(struct ref_fm));
  1045.             fm_tmp_ref_alloc=1;
  1046.         }
  1047.         fm_tmp_ref->refs_used=1;
  1048.         fm_tmp_ref->fm_refs[0].ref_row=r;
  1049.         fm_tmp_ref->fm_refs[0].ref_col=c;
  1050.     } else {
  1051.         if(fm_tmp_ref_alloc<=from->refs_used) {
  1052.  
  1053.             fm_tmp_ref=ck_realloc(fm_tmp_ref,sizeof(struct ref_fm)
  1054.                     +from->refs_used*sizeof(struct ref_array));
  1055.             fm_tmp_ref_alloc=from->refs_used+1;
  1056.         }
  1057.         fm_tmp_ref->refs_used=from->refs_used+1;
  1058.         n=0;
  1059.         while(n<from->refs_used
  1060.             && (from->fm_refs[n].ref_row<r
  1061.                || (from->fm_refs[n].ref_row==r && from->fm_refs[n].ref_col<=c))) {
  1062.             fm_tmp_ref->fm_refs[n]=from->fm_refs[n];
  1063.             n++;
  1064.         }
  1065.         fm_tmp_ref->fm_refs[n].ref_row=r;
  1066.         fm_tmp_ref->fm_refs[n].ref_col=c;
  1067.         while(n<from->refs_used) {
  1068.             fm_tmp_ref->fm_refs[n+1]=from->fm_refs[n];
  1069.             n++;
  1070.         }
  1071.     }
  1072.     *where=find_fm_ref();
  1073.     if(from)
  1074.         flush_fm_ref(from);
  1075. }
  1076.  
  1077. static void
  1078. flush_ref_fm FUN3(struct ref_fm **, where, CELLREF, r, CELLREF, c)
  1079. {
  1080.     struct ref_fm *from;
  1081.     int n;
  1082.  
  1083.     from= *where;
  1084. #ifdef TEST
  1085.     if(!from) {
  1086.         error_msg("No refs in flush_ref_fm(%p,%u,%u)",where,r,c);
  1087.         return;
  1088.     }
  1089. #endif
  1090.     if(from->refs_used==1) {
  1091.         *where=0;
  1092.         flush_fm_ref(from);
  1093.         return;
  1094.     }
  1095.     fm_tmp_ref->refs_used=from->refs_used-1;
  1096.     n=0;
  1097.     while(n<from->refs_used
  1098.         && (from->fm_refs[n].ref_row<r
  1099.            || (from->fm_refs[n].ref_row==r && from->fm_refs[n].ref_col<c))) {
  1100.         fm_tmp_ref->fm_refs[n]=from->fm_refs[n];
  1101.         n++;
  1102.     }
  1103. #ifdef TEST
  1104.     if(n==from->refs_used) {
  1105.         error_msg("No refs from %u,%u in %p in flush_refs_fm",r,c,where);
  1106.         return;
  1107.     }
  1108. #endif
  1109.     while(n<fm_tmp_ref->refs_used) {
  1110.         fm_tmp_ref->fm_refs[n]=from->fm_refs[n+1];
  1111.         n++;
  1112.     }
  1113.     *where=find_fm_ref();
  1114.     flush_fm_ref(from);
  1115. }
  1116.  
  1117. #ifdef TEST
  1118. extern char print_buf[];
  1119.  
  1120. void
  1121. dbg_print_ref_fm FUN1(struct ref_fm *,rf)
  1122. {
  1123.     int nr;
  1124.     char *bufp;
  1125.  
  1126.     if(rf) {
  1127.         text_line("fm %p: refcnt %u  next %p  used %u",
  1128.             rf,rf->refs_refcnt,rf->refs_next,rf->refs_used);
  1129.         for(nr=0,bufp=print_buf;nr<rf->refs_used;nr++) {
  1130.             (void)sprintf(bufp," %s",cell_name(rf->fm_refs[nr].ref_row,rf->fm_refs[nr].ref_col));
  1131.             if(nr%10==9) {
  1132.                 text_line(print_buf);
  1133.                 bufp=print_buf;
  1134.             } else
  1135.                 bufp+=strlen(bufp);
  1136.         }
  1137.         if(nr%10)
  1138.             text_line(print_buf);
  1139.     }
  1140. }
  1141. #endif
  1142.  
  1143. static struct ref_to *
  1144. find_to_ref FUN0()
  1145. {
  1146.     struct ref_to *tmp;
  1147.     int n;
  1148.     unsigned long hash;
  1149.  
  1150.     /* error_msg("find_to_ref %u %u",to_tmp_ref->refs_used,to_tmp_ref->to_refs[0]); */
  1151. #if 1
  1152.     for(hash=0,n=0;n<to_tmp_ref->refs_used;n++)
  1153.         hash+= (n+1) * to_tmp_ref->to_refs[n];
  1154.  
  1155.     hash%=TO_HASH_NUM;
  1156. #else
  1157.     hash=to_tmp_ref->refs_used;
  1158. #endif
  1159.     for(tmp=to_list[hash];tmp;tmp=tmp->refs_next) {
  1160.         /* error_msg("%p(%u)->%p  %u %u",tmp,tmp->refs_refcnt,
  1161.             tmp->refs_next,tmp->refs_used,tmp->to_refs[0]); */
  1162.         if(tmp->refs_used!=to_tmp_ref->refs_used)
  1163.             continue;
  1164.         if(!bcmp(tmp->to_refs,to_tmp_ref->to_refs,to_tmp_ref->refs_used)) {
  1165.             /* error_msg("Hit!"); */
  1166.             tmp->refs_refcnt++;
  1167.             return tmp;
  1168.         }
  1169. #ifdef TEST
  1170.         else
  1171.             to_misses++;
  1172. #endif
  1173.     }
  1174.  
  1175.     /* error_msg("Miss. .."); */
  1176.     tmp=ck_malloc(sizeof(struct ref_to)+to_tmp_ref->refs_used-1);
  1177.     tmp->refs_next=to_list[hash];
  1178.     to_list[hash]=tmp;
  1179.     tmp->refs_refcnt=1;
  1180.     tmp->refs_used=to_tmp_ref->refs_used;
  1181.     bcopy(to_tmp_ref->to_refs,tmp->to_refs,tmp->refs_used);
  1182.  
  1183.     return tmp;
  1184. }
  1185.  
  1186. void
  1187. add_ref_to FUN1(int, whereto)
  1188. {
  1189.     struct ref_to *from;
  1190.     int n;
  1191.  
  1192.     from= my_cell->cell_refs_to;
  1193.     if(!from) {
  1194.         if(!to_tmp_ref) {
  1195.             to_tmp_ref=ck_malloc(sizeof(struct ref_to));
  1196.             to_tmp_ref_alloc=1;
  1197.         }
  1198.         to_tmp_ref->refs_used=1;
  1199.         to_tmp_ref->to_refs[0]=whereto;
  1200.     } else {
  1201.         if(to_tmp_ref_alloc<=from->refs_used) {
  1202.  
  1203.             to_tmp_ref=ck_realloc(to_tmp_ref,sizeof(struct ref_to) +from->refs_used);
  1204.             to_tmp_ref_alloc=from->refs_used+1;
  1205.         }
  1206.         to_tmp_ref->refs_used=from->refs_used+1;
  1207.         n=0;
  1208.         while(n<from->refs_used && from->to_refs[n]<whereto) {
  1209.             to_tmp_ref->to_refs[n]=from->to_refs[n];
  1210.             n++;
  1211.         }
  1212.         to_tmp_ref->to_refs[n]=whereto;
  1213.         while(n<from->refs_used) {
  1214.             to_tmp_ref->to_refs[n+1]=from->to_refs[n];
  1215.             n++;
  1216.         }
  1217.         flush_ref_to(&(my_cell->cell_refs_to));
  1218.     }
  1219.     my_cell->cell_refs_to=find_to_ref();
  1220. }
  1221.  
  1222. static void
  1223. flush_ref_to FUN1(struct ref_to **,where)
  1224. {
  1225.     struct ref_to *tmp;
  1226.     struct ref_to *old;
  1227.     int n;
  1228.     unsigned long hash;
  1229.  
  1230. #ifdef TEST
  1231.     if(!where || !*where) {
  1232.         error_msg("null flush_ref_to(%p)",where);
  1233.         return;
  1234.     }
  1235. #endif
  1236.     old= *where;
  1237.     *where=0;
  1238.     --(old->refs_refcnt);
  1239.  
  1240. #ifdef DEFER_FREE
  1241.     return;
  1242. #endif
  1243.     if(!old->refs_refcnt) {
  1244. #if 1
  1245.         for(hash=0,n=0;n<old->refs_used;n++)
  1246.             hash+=(n+1) * old->to_refs[n];
  1247.  
  1248.         hash%=TO_HASH_NUM;
  1249. #else
  1250.         hash=old->refs_used;
  1251. #endif
  1252.         if(to_list[hash]==old)
  1253.             to_list[hash]=old->refs_next;
  1254.         else {
  1255.             for(tmp=to_list[hash];tmp && tmp->refs_next!=old;tmp=tmp->refs_next)
  1256.                 ;
  1257. #ifdef TEST
  1258.             if(!tmp) {
  1259.                 error_msg("Old not in refs_list in flush_to_ref(%p)",old);
  1260.                 return;
  1261.             }
  1262. #endif
  1263.             tmp->refs_next=old->refs_next;
  1264.         }
  1265.         free(old);
  1266.     }
  1267. }
  1268.  
  1269. #ifdef TEST
  1270. void
  1271. dbg_print_ref_to FUN2(struct ref_to *,rt, unsigned char *,form)
  1272. {
  1273.     int nr;
  1274.     char *bufp;
  1275.  
  1276.     if(rt) {
  1277.         text_line("to %p: refcnt %u  next %p  used %u",
  1278.             rt,rt->refs_refcnt,rt->refs_next,rt->refs_used);
  1279.         for(nr=0,bufp=print_buf;nr<rt->refs_used;nr++) {
  1280.             (void)sprintf(bufp," %3d (%#4x)",rt->to_refs[nr],form[rt->to_refs[nr]]);
  1281.             if(nr%7==6) {
  1282.                 text_line(print_buf);
  1283.                 bufp=print_buf;
  1284.             } else
  1285.                 bufp+=strlen(bufp);
  1286.         }
  1287.         if(nr%7)
  1288.             text_line(print_buf);
  1289.     }
  1290. }
  1291.  
  1292. void
  1293. ref_stats FUN0()
  1294. {
  1295.     int n;
  1296.     int cur;
  1297.     struct ref_fm *rf;
  1298.     struct ref_to *rt;
  1299.  
  1300.     int rf_max = 0;
  1301.     int rf_num = 0;
  1302.     int rf_shared = 0;
  1303.     int rf_saved = 0;
  1304.     int rf_zero = 0;
  1305.  
  1306.     int rt_max = 0;
  1307.     int rt_num = 0;
  1308.     int rt_shared = 0;
  1309.     int rt_saved = 0;
  1310.     int rt_zero = 0;
  1311.  
  1312.     for(n=0;n<FM_HASH_NUM;n++) {
  1313.         cur=0;
  1314.         for(rf=fm_list[n];rf;rf=rf->refs_next) {
  1315.             if(rf->refs_refcnt==0)
  1316.                 rf_zero++;
  1317.             if(rf->refs_refcnt>1) {
  1318.                 rf_shared++;
  1319.                 rf_saved+=rf->refs_refcnt-1;
  1320.             }
  1321.             rf_num++;
  1322.             cur++;
  1323.         }
  1324.         if(cur>rf_max)
  1325.             rf_max=cur;
  1326.     }
  1327.     for(n=0;n<TO_HASH_NUM;n++) {
  1328.         cur=0;
  1329.         for(rt=to_list[n];rt;rt=rt->refs_next) {
  1330.             if(rt->refs_refcnt==0)
  1331.                 rt_zero++;
  1332.             if(rt->refs_refcnt>1) {
  1333.                 rt_shared++;
  1334.                 rt_saved+=rt->refs_refcnt-1;
  1335.             }
  1336.             rt_num++;
  1337.             cur++;
  1338.         }
  1339.         if(cur>rt_max)
  1340.             rt_max=cur;
  1341.     }
  1342.     text_line("from: %d refs, max_length %d, shared %d, saved %d, zero_ref %d, missed %d\n",rf_num,rf_max,rf_shared,rf_saved,rf_zero,fm_misses);
  1343.     text_line("to: %d refs, max_length %d, shared %d, saved %d, zero_ref %d, missed %d\n",rt_num,rt_max,rt_shared,rt_saved,rt_zero,to_misses);
  1344. }
  1345. #endif
  1346. #else
  1347.  
  1348. static void
  1349. add_ref_fm FUN3(struct ref_fm **, where, CELLREF, r, CELLREF, c)
  1350. {
  1351.     struct ref_fm *ref;
  1352.  
  1353.     ref= *where;
  1354.     if(!ref) {
  1355.         *where=ref=ck_malloc(sizeof(struct ref_fm)+(REF_START-1)*sizeof(struct ref_array));
  1356.         ref->refs_alloc=REF_START;
  1357.         ref->refs_used=0;
  1358.     } else if(ref->refs_alloc==ref->refs_used) {
  1359.         ref->refs_alloc REF_INC;
  1360.  
  1361.         *where=ref=ck_realloc(ref, sizeof(struct ref_fm)+(ref->refs_alloc-1)*sizeof(struct ref_array));
  1362.     }
  1363.     ref->fm_refs[ref->refs_used].ref_row=r;
  1364.     ref->fm_refs[ref->refs_used].ref_col=c;
  1365.     ref->refs_used++;
  1366. }
  1367.  
  1368. static void
  1369. flush_ref_fm FUN3(struct ref_fm **, where, CELLREF, r, CELLREF, c)
  1370. {
  1371.     int n;
  1372.     struct ref_fm *ref;
  1373.  
  1374.     ref= *where;
  1375. #ifdef TEST
  1376.     if(!ref) {
  1377.         error_msg("%s->No refs in flush_ref_fm(%d,%d)",cell_name(cur_row,cur_col),r,c);
  1378.         return;
  1379.     }
  1380. #endif
  1381.     for(n=0;n<ref->refs_used;n++)
  1382.         if(ref->fm_refs[n].ref_row==r && ref->fm_refs[n].ref_col==c) {
  1383.             ref->fm_refs[n]=ref->fm_refs[ref->refs_used-1];
  1384.             --(ref->refs_used);
  1385.             return;
  1386.         }
  1387. #ifdef TEST
  1388.     error_msg("%s->Can't flush_ref_fm(%d,%d)",cell_name(cur_row,cur_col),r,c);
  1389.     return;
  1390. #endif
  1391. }
  1392.  
  1393. void
  1394. add_ref_to FUN1(int, whereto)
  1395. {
  1396.     struct ref_to *ref;
  1397.  
  1398.     ref= my_cell->cell_refs_to;
  1399.     if(!ref) {
  1400.         my_cell->cell_refs_to=ref=ck_malloc(sizeof(struct ref_to)+(REF_START-1)*sizeof(unsigned char));
  1401.         ref->refs_alloc=REF_START;
  1402.         ref->refs_used=0;
  1403.     } else if(ref->refs_alloc==ref->refs_used) {
  1404.         ref->refs_alloc REF_INC;
  1405.  
  1406.         my_cell->cell_refs_to=ref=ck_realloc(ref, sizeof(struct ref_to)+
  1407.         (ref->refs_alloc-1)*sizeof(unsigned char));
  1408.     }
  1409.     ref->to_refs[ref->refs_used]=whereto;
  1410.     ref->refs_used++;
  1411. }
  1412.  
  1413. #ifdef TEST
  1414.  
  1415. void
  1416. dbg_print_ref_fm FUN1(struct ref_fm *,rf)
  1417. {
  1418.     int nr;
  1419.     char *bufp;
  1420.  
  1421.     if(rf) {
  1422.         text_line("fm %p: alloc %u  used %u",
  1423.             rf,rf->refs_alloc,rf->refs_used);
  1424.         for(nr=0,bufp=print_buf;nr<rf->refs_used;nr++) {
  1425.             (void)sprintf(bufp," %s",cell_name(rf->fm_refs[nr].ref_row,rf->fm_refs[nr].ref_col));
  1426.             if(nr%10==9) {
  1427.                 text_line(print_buf);
  1428.                 bufp=print_buf;
  1429.             } else
  1430.                 bufp+=strlen(bufp);
  1431.         }
  1432.         if(nr%10)
  1433.             text_line(print_buf);
  1434.     }
  1435. }
  1436.  
  1437. void
  1438. dbg_print_ref_to FUN2(struct ref_to *,rt, unsigned char *,form)
  1439. {
  1440.     int nr;
  1441.     char *bufp;
  1442.  
  1443.     if(rt) {
  1444.         text_line("to %p:  alloc %u  used %u",
  1445.             rt,rt->refs_alloc,rt->refs_used);
  1446.         for(nr=0,bufp=print_buf;nr<rt->refs_used;nr++) {
  1447.             (void)sprintf(bufp," %3d (%#4x)",rt->to_refs[nr],form[rt->to_refs[nr]]);
  1448.             if(nr%7==6) {
  1449.                 text_line(print_buf);
  1450.                 bufp=print_buf;
  1451.             } else
  1452.                 bufp+=strlen(bufp);
  1453.         }
  1454.         if(nr%7)
  1455.             text_line(print_buf);
  1456.     }
  1457. }
  1458.  
  1459. void
  1460. ref_stats FUN0()
  1461. {
  1462.     CELL *cp;
  1463.     extern struct rng all_rng;
  1464.  
  1465.     int rf_num = 0;
  1466.     int rf_zero = 0;
  1467.     int rf_biggest = 0;
  1468.  
  1469.     int rt_num = 0;
  1470.     int rt_zero = 0;
  1471.     int rt_biggest = 0;
  1472.  
  1473.     find_cells_in_range(&all_rng);
  1474.     while(cp=next_cell_in_range()) {
  1475.         if(cp->cell_refs_from) {
  1476.             if(cp->cell_refs_from->refs_used>rf_biggest)
  1477.                 rf_biggest=cp->cell_refs_from->refs_used;
  1478.             if(cp->cell_refs_from->refs_used==0)
  1479.                 rf_zero++;
  1480.             rf_num++;
  1481.         }
  1482.         if(cp->cell_refs_to) {
  1483.             if(cp->cell_refs_to->refs_used>rt_biggest)
  1484.                 rt_biggest=cp->cell_refs_to->refs_used;
  1485.             if(cp->cell_refs_to->refs_used==0)
  1486.                 rt_zero++;
  1487.             rt_num++;
  1488.         }
  1489.     }
  1490.     text_line("from: %d refs, biggest %d, zero_ref %d\n",rf_num,rf_biggest,rf_zero);
  1491.     text_line("to: %d refs, biggest %d,zero_ref %d\n",rt_num,rt_biggest,rt_zero);
  1492. }
  1493. #endif
  1494.  
  1495. #endif
  1496.  
  1497. /* ------------- Routines for dealing with moving cells -------------------- */
  1498.  
  1499. static struct rng *shift_fm;
  1500. static int shift_ov;
  1501. static int shift_dn;
  1502.  
  1503. static void shift_var FUN2(char *,name, struct var *,v)
  1504. {
  1505.     int n;
  1506.     int nn;
  1507.  
  1508.  
  1509.     n=   (BETWEEN(v->v_rng.hc,shift_fm->lc,shift_fm->hc)<<3)
  1510.        + (BETWEEN(v->v_rng.lc,shift_fm->lc,shift_fm->hc)<<2)
  1511.        + (BETWEEN(v->v_rng.hr,shift_fm->lr,shift_fm->hr)<<1)
  1512.        + BETWEEN(v->v_rng.lr,shift_fm->lr,shift_fm->hr);
  1513.     switch(n) {
  1514.     case 0:
  1515.     case 1:
  1516.     case 2:
  1517.     case 3:
  1518.     case 4:
  1519.     case 8:
  1520.     case 12:
  1521.         /* Null intersection, ignore it */
  1522.         break;
  1523.  
  1524.     case 5: /* The bottom and right */
  1525.     case 6: /* The bottom and left */
  1526.     case 9: /* The top and right */
  1527.     case 10:/* The top and left */
  1528.         /* The var sticks out of the range we're moving */
  1529.         /* on two sides.  what should we do? */
  1530.         error_msg("'%s' can't be adjusted",v->var_name);
  1531.         break;
  1532.  
  1533.     case 7: /* v->hc sticks out the right */
  1534.     case 11:/* v->lc sticks out the left */
  1535.     case 13:/* v->hr sticks out the bottom */
  1536.     case 14:/* v->lr sticks out the top */
  1537.         /* It only sticks out on one side.  We can
  1538.            (try to) adjust it */
  1539.         error_msg("'%s' sticks out; adjusted",v->var_name);
  1540.     case 15:    /* var is completely inside the range */
  1541.         if(v->var_ref_fm) {
  1542.             for(nn=0;nn<v->var_ref_fm->refs_used;nn++) {
  1543.                 flush_range_ref(&(v->v_rng),
  1544.                     v->var_ref_fm->fm_refs[nn].ref_row,
  1545.                     v->var_ref_fm->fm_refs[nn].ref_col);
  1546.             }
  1547.         }
  1548.         if(n!=7)
  1549.             v->v_rng.hc+=shift_ov;
  1550.         if(n!=11)
  1551.             v->v_rng.lc+=shift_ov;
  1552.         if(n!=13)
  1553.             v->v_rng.hr+=shift_dn;
  1554.         if(n!=14)
  1555.             v->v_rng.lr+=shift_dn;
  1556.         if(!v->var_ref_fm)
  1557.             return;
  1558.  
  1559.         for(n=0;n<v->var_ref_fm->refs_used;n++) {
  1560.             cur_row=v->var_ref_fm->fm_refs[n].ref_row;
  1561.             cur_col=v->var_ref_fm->fm_refs[n].ref_col;
  1562.             add_range_ref(&(v->v_rng));
  1563.         }
  1564.         break;
  1565. #ifdef TEST
  1566.     default:
  1567.         panic("Bad ###%d",n);
  1568. #endif
  1569.     }
  1570. }
  1571.  
  1572. /* All the cells in FM are about to move down DN and over OV, adjust
  1573.    everything outside them, etc so that it-all will still work.  This is
  1574.    a horrible, but required kludge.
  1575.  */
  1576. void
  1577.   shift_outside FUN3(struct rng *,fm, int,dn, int,ov)
  1578. {
  1579.   CELL *cp;
  1580.   CELL *fcp;
  1581.   CELL *tcp;
  1582.   int n;
  1583.   int fn;
  1584.   CELLREF rr,cc;
  1585.   CELLREF frr,fcc;
  1586.   CELLREF trr,tcc;
  1587.   unsigned char *ffp;
  1588.   unsigned char *fp;
  1589.   struct var *v;
  1590.   struct rng orng;
  1591.   
  1592.   char *ptr;
  1593.   unsigned long val;
  1594.   static char DEF_REF[] = "DEFREF";
  1595.   static char DEF_RNG[] = "DEFRNG";
  1596.   
  1597.   /* This moves all the variables in FM down DN and over OV
  1598.      This also adjusts *all* references to these variables */
  1599.   
  1600.   shift_fm=fm;
  1601.   shift_dn=dn;
  1602.   shift_ov=ov;
  1603.   for_all_vars(shift_var);
  1604.   
  1605.   /* We use this stack 'cuz we might need to move a reference to
  1606.      somewhere else in the range we're scanning.  If we do, without the
  1607.      defer stack, we may accidentally move the reference again. */
  1608.   if(!moving)
  1609.     moving=init_stack();
  1610.   
  1611.   find_cells_in_range(fm);
  1612.   while(cp=next_row_col_in_range(&rr,&cc)) {
  1613.     
  1614.     /* Adjust references from inside the region */
  1615.     if(cp->cell_refs_to) {
  1616.       for(n=0;n<cp->cell_refs_to->refs_used;n++) {
  1617.     fp= &(cp->cell_formula[cp->cell_refs_to->to_refs[n]]);
  1618.     switch(*fp) {
  1619.     case R_CELL:
  1620.     case R_CELL|ROWREL:
  1621.     case R_CELL|COLREL:
  1622.     case R_CELL|ROWREL|COLREL:
  1623.       trr=GET_ROW(fp+1);
  1624.       tcc=GET_COL(fp+1);
  1625.       tcp=find_cell(trr,tcc);
  1626. #ifdef TEST
  1627.       if(!tcp)
  1628.         panic("Can't find_cell(%s) for %d ref from %s in shift_stuff()",cell_name(trr,tcc),*fp,cell_name(rr,cc));
  1629. #endif
  1630.       fn=BETWEEN(trr,fm->lr,fm->hr) && BETWEEN(tcc,fm->lc,fm->hc);
  1631. /*      frr= MIN(MAX_R,MAX(MIN_R,(fn || (((*fp)&ROWREL))) ? trr+dn : trr));
  1632.       fcc= MIN(MAX_C,MAX(MIN_C,(fn || (((*fp)&COLREL))) ? tcc+ov : tcc));*/
  1633.   /* MIN,MAX crap insures frr and fcc are within bounds, this should
  1634.      produce an error if out of bounds, but how????, pass travis */
  1635.       frr= (fn || (((*fp)&ROWREL))) ? trr+dn : trr;
  1636.       if (frr>MAX_R || frr<MIN_R ) {frr=MAX_R; fcc=MAX_C;}
  1637.       fcc= (fn || (((*fp)&COLREL))) ? tcc+ov : tcc;
  1638.       if (fcc>MAX_C || fcc<MIN_C )  {frr=MAX_R; fcc=MAX_C;}
  1639. /* this way if out of bounds, point cell to the last cell, and hope for an error */
  1640.       if(frr!=trr || fcc!=tcc) {
  1641.         flush_ref_fm(&(tcp->cell_refs_from),rr,cc);
  1642.         PUT_ROW(fp+1,frr);
  1643.         PUT_COL(fp+1,fcc);
  1644.         if(BETWEEN(frr,fm->lr,fm->hr) && BETWEEN(fcc,fm->lc,fm->hc)) {
  1645.           push_stack(moving,(VOIDSTAR)TO_MAGIC(rr,cc));
  1646.           push_stack(moving,(VOIDSTAR)TO_MAGIC(frr,fcc));
  1647.           push_stack(moving,DEF_REF);
  1648.         } else {
  1649.           tcp=find_or_make_cell(frr,fcc);
  1650.           add_ref_fm(&(tcp->cell_refs_from),rr+dn,cc+ov);
  1651.           cp=find_cell(rr,cc);
  1652.         }
  1653.       }
  1654.       break;
  1655.       
  1656.     case RANGE:
  1657.     case RANGE|LRREL:
  1658.     case RANGE|HRREL:
  1659.     case RANGE|LCREL:
  1660.     case RANGE|HCREL:
  1661.     case RANGE|LRREL|HRREL:
  1662.     case RANGE|LRREL|LCREL:
  1663.     case RANGE|LRREL|HCREL:
  1664.     case RANGE|HRREL|LCREL:
  1665.     case RANGE|HRREL|HCREL:
  1666.     case RANGE|LCREL|HCREL:
  1667.     case RANGE|LRREL|LCREL|HCREL:
  1668.     case RANGE|LRREL|HRREL|LCREL:
  1669.     case RANGE|LRREL|HRREL|HCREL:
  1670.     case RANGE|HRREL|LCREL|HCREL:
  1671.     case RANGE|LRREL|HRREL|LCREL|HCREL:
  1672.       GET_RNG(fp+1,&orng);
  1673.       flush_range_ref(&orng,rr,cc);
  1674.       
  1675.       fn=   (BETWEEN(orng.hc,fm->lc,fm->hc)<<3)
  1676.         | (BETWEEN(orng.lc,fm->lc,fm->hc)<<2)
  1677.           | (BETWEEN(orng.hr,fm->lr,fm->hr)<<1)
  1678.         |  BETWEEN(orng.lr,fm->lr,fm->hr);
  1679.       
  1680.       switch(fn) {
  1681.       case 3:
  1682.       case 5:
  1683.       case 6:
  1684.       case 9:
  1685.       case 10:
  1686.       case 12:
  1687.         error_msg("Range %s at cell %s can't be adjusted",range_name(&orng),cell_name(rr,cc));
  1688.         /* Fallthrough */
  1689.       case 0:
  1690.       case 1:
  1691.       case 2:
  1692.       case 4:
  1693.       case 8:
  1694.         if((*fp)&LRREL)
  1695.           orng.lr+=dn;
  1696.         if((*fp)&HRREL)
  1697.           orng.hr+=dn;
  1698.         if((*fp)&LCREL)
  1699.           orng.lc+=ov;
  1700.         if((*fp)&HCREL)
  1701.           orng.hc+=ov;
  1702.         break;
  1703.         
  1704.       case 7:
  1705.       case 11:
  1706.       case 13:
  1707.       case 14:
  1708.         error_msg("Range %s sticks out at cell %s; adjusted",range_name(&orng),cell_name(rr,cc));
  1709.         /* Fallthrough */
  1710.       case 15:
  1711.         if(fn!=7)
  1712.           orng.hc+=ov;
  1713.         if(fn!=11)
  1714.           orng.lc+=ov;
  1715.         if(fn!=13)
  1716.           orng.hr+=dn;
  1717.         if(fn!=14)
  1718.           orng.lr+=dn;
  1719.         break;
  1720. #ifdef TEST
  1721.       default:
  1722.         panic("fn==%d?",fn);
  1723. #endif
  1724.       }
  1725.       PUT_RNG(fp+1,&orng);
  1726.       cur_row=rr;
  1727.       cur_col=cc;
  1728.       add_range_ref(&orng);
  1729.       break;
  1730.     default:
  1731.       {
  1732.         struct function *fun;
  1733.         
  1734.         if(*fp<USR1)
  1735.           fun= &the_funs[*fp];
  1736. #ifdef TEST
  1737.         else if(*fp>=SKIP)
  1738.           fun=0,panic("SKIP?? in shift_outside()");
  1739. #endif
  1740.         else
  1741.           fun= &usr_funs[*fp][fp[1]];
  1742.         
  1743.         if(fun->fn_comptype&C_T) {
  1744.           flush_ref_fm(&timer_cells,rr,cc);
  1745.           add_ref_fm(&timer_cells,rr+dn,cc+ov);
  1746.         }
  1747.       }
  1748.       break;
  1749.     }
  1750.     
  1751.       }
  1752.     }
  1753.     
  1754.     /* If nothing referenced them, don't worry about them */
  1755.     if(!cp->cell_refs_from)
  1756.       continue;
  1757.     for(n=0;n<cp->cell_refs_from->refs_used;n++) {
  1758.       
  1759.       /* For each cell that referenced this one, look
  1760.      at the type of reference involved */
  1761.       frr=cp->cell_refs_from->fm_refs[n].ref_row;
  1762.       fcc=cp->cell_refs_from->fm_refs[n].ref_col;
  1763.       /* Unless it's from inside the region we're moving */
  1764.       if(BETWEEN(frr,fm->lr,fm->hr) && BETWEEN(fcc,fm->lc,fm->hc))
  1765.     continue;
  1766.       
  1767.       fcp=find_cell(frr,fcc);
  1768. #ifdef TEST
  1769.       if(!fcp || !fcp->cell_formula || !fcp->cell_refs_to)
  1770.     panic("How'd we get this cell");
  1771. #endif
  1772.       for(fn=0;fn<fcp->cell_refs_to->refs_used;fn++) {
  1773.     ffp= &(fcp->cell_formula[fcp->cell_refs_to->to_refs[fn]]);
  1774.     switch(*ffp) {
  1775.     case R_CELL:
  1776.     case R_CELL|ROWREL:
  1777.     case R_CELL|COLREL:
  1778.     case R_CELL|ROWREL|COLREL:
  1779.       trr=GET_ROW(ffp+1);
  1780.       tcc=GET_COL(ffp+1);
  1781.       if(trr!=rr || tcc!=cc)
  1782.         /* Not the one we're looking for */
  1783.         break;
  1784.       
  1785.       /* Found it!  Find the cell that fcp
  1786.          should be referencing now */
  1787.       if(!((*ffp)&ROWREL)) {
  1788.         trr+=dn;
  1789.         PUT_ROW(ffp+1, trr);
  1790.       }
  1791.       if(!((*ffp)&COLREL)) {
  1792.         tcc+=ov;
  1793.         PUT_COL(ffp+1, tcc);
  1794.       } else
  1795.         goto nxtref;
  1796.       
  1797.       if(BETWEEN(trr,fm->lr,fm->hr) && BETWEEN(tcc,fm->lc,fm->hc)) {
  1798.         push_stack(moving,(VOIDSTAR )TO_MAGIC(frr,fcc));
  1799.         push_stack(moving,(VOIDSTAR )TO_MAGIC(trr,tcc));
  1800.         push_stack(moving,DEF_REF);
  1801.       } else {
  1802.         cp=find_or_make_cell(trr,tcc);
  1803.         add_ref_fm(&(cp->cell_refs_from),frr,fcc);
  1804.       }
  1805.       goto flushref;
  1806.       
  1807.     case VAR:
  1808.       bcopy(&ffp[1],&v,sizeof(struct var *));
  1809.       switch(v->var_flags) {
  1810.       case VAR_UNDEF:
  1811.         break;
  1812.         
  1813.       case VAR_CELL:
  1814.         if(v->v_rng.lr==rr || v->v_rng.lc==cc)
  1815.           /* Right variable */
  1816.           goto nxtref;
  1817.         break;
  1818.         
  1819.       case VAR_RANGE:
  1820.         if(BETWEEN(rr,v->v_rng.lr,v->v_rng.hr) && BETWEEN(cc,v->v_rng.lc,v->v_rng.hc))
  1821.           goto nxtref;
  1822.         break;
  1823. #ifdef TEST
  1824.       default:
  1825.         panic("Unknown variable flags %d (%s)",v->var_flags,v->var_name);
  1826. #endif
  1827.       }
  1828.       break;
  1829.       
  1830.     case RANGE:
  1831.     case RANGE|LRREL:
  1832.     case RANGE|LRREL|LCREL:
  1833.     case RANGE|LRREL|LCREL|HCREL:
  1834.     case RANGE|LRREL|HCREL:
  1835.     case RANGE|LRREL|HRREL:
  1836.     case RANGE|LRREL|HRREL|LCREL:
  1837.     case RANGE|LRREL|HRREL|LCREL|HCREL:
  1838.     case RANGE|LRREL|HRREL|HCREL:
  1839.     case RANGE|HRREL:
  1840.     case RANGE|HRREL|LCREL:
  1841.     case RANGE|HRREL|LCREL|HCREL:
  1842.     case RANGE|HRREL|HCREL:
  1843.     case RANGE|LCREL:
  1844.     case RANGE|LCREL|HCREL:
  1845.     case RANGE|HCREL:
  1846.       GET_RNG(ffp+1,&orng);
  1847.       
  1848.       if(!BETWEEN(rr,orng.lr,orng.hr) || !BETWEEN(cc,orng.lc,orng.hc))
  1849.         break;
  1850.       
  1851.       val=   (BETWEEN(orng.hc,fm->lc,fm->hc)<<3)
  1852.         + (BETWEEN(orng.lc,fm->lc,fm->hc)<<2)
  1853.           + (BETWEEN(orng.hr,fm->lr,fm->hr)<<1)
  1854.         +  BETWEEN(orng.lr,fm->lr,fm->hr);
  1855.       
  1856.       if(!(       *ffp==RANGE
  1857.            || (!dn && ((*ffp)|LRREL|HRREL)==(RANGE|LRREL|HRREL))
  1858.            || (!ov && ((*ffp)|LCREL|HCREL)==(RANGE|LCREL|HCREL))))
  1859.         goto nxtref;
  1860.       
  1861.       if(val!=7 && val!=11 && val!=13 && val!=14 && val!=15) {
  1862. #ifdef TEST
  1863.         error_msg("Val %d?",val);
  1864. #endif
  1865.         goto nxtref;
  1866.       } else if(val!=15)
  1867.         error_msg("adjusting range %s at %s",range_name(&orng),cell_name(frr,fcc));
  1868.       
  1869.       /* Move the entire damn range */
  1870.       flush_range_ref(&orng,frr,fcc);
  1871.       
  1872.       if(val!=14)
  1873.         orng.lr+=dn;
  1874.       if(val!=13)
  1875.         orng.hr+=dn;
  1876.       if(val!=11)
  1877.         orng.lc+=ov;
  1878.       if(val!=7)
  1879.         orng.hc+=ov;
  1880.       PUT_RNG(ffp+1,&orng);
  1881.       push_stack(moving,(VOIDSTAR)ffp);
  1882.       push_stack(moving,(VOIDSTAR )TO_MAGIC(frr,fcc));
  1883.       push_stack(moving,DEF_RNG);
  1884.       --n;
  1885.       goto nxtref;
  1886. #ifdef TEST
  1887.     default:
  1888.       {
  1889.         struct function *fun;
  1890.         
  1891.         if(*ffp<USR1)
  1892.           fun= &the_funs[*ffp];
  1893.         else if(*ffp>=SKIP)
  1894.           fun=0,panic("SKIP? in shift_outside()");
  1895.         else
  1896.           fun= &usr_funs[*ffp][ffp[1]];
  1897.         if((fun->fn_comptype&C_T)==0)
  1898.           error_msg("Unknown byte (%d) for reference_to #%d %d",*ffp,fn,fcp->cell_refs_to->to_refs[fn]);
  1899.       }
  1900.       break;
  1901. #endif
  1902.     }
  1903.       }
  1904. #ifdef TEST
  1905.       error_msg("No refs_to at %s to explain ref_fm at %s",cell_name(frr,fcc),cell_name(rr,cc));
  1906.       break;
  1907. #endif
  1908.     flushref:
  1909.       /* If we get here, the ref from frr,fcc should be
  1910.      deleted. */
  1911.       flush_ref_fm(&(cp->cell_refs_from),frr,fcc);
  1912.       --n;
  1913.       
  1914.       
  1915.     nxtref:
  1916.       /* If we get here, we found the reference we were
  1917.      looking for and we want to go on to the next one */
  1918.       ;
  1919.     }
  1920.   }
  1921.   while(ptr=pop_stack(moving)) {
  1922.     if(ptr==DEF_REF) {
  1923.       val=(unsigned long)pop_stack(moving);
  1924.       trr=MAGIC_ROW(val);
  1925.       tcc=MAGIC_COL(val);
  1926.       val=(unsigned long)pop_stack(moving);
  1927.       cp=find_or_make_cell(trr,tcc);
  1928.       add_ref_fm(&(cp->cell_refs_from),MAGIC_ROW(val),MAGIC_COL(val));
  1929.     } else if(ptr==DEF_RNG) {
  1930.       val=(unsigned long)pop_stack(moving);
  1931.       cur_row=MAGIC_ROW(val);
  1932.       cur_col=MAGIC_COL(val);
  1933.       ffp=(unsigned char *)pop_stack(moving);
  1934.       
  1935.       GET_RNG(ffp+1,&orng);
  1936.       add_range_ref(&orng);
  1937.     }
  1938. #ifdef TEST
  1939.     else
  1940.       panic("Now what (%p)?",ptr);
  1941. #endif
  1942.   }
  1943.   /* flush_stack(moving); */
  1944. }
  1945.  
  1946. /* The formula in cell my_cell has moved by DN down and OV over, adjust
  1947.    everything so it'll still work */
  1948. void
  1949. shift_formula FUN2(int,dn, int,ov)
  1950. {
  1951.     int n;
  1952.     unsigned char *fp;
  1953.  
  1954.     for(n=0;n<my_cell->cell_refs_to->refs_used;n++) {
  1955.         fp= &(my_cell->cell_formula[my_cell->cell_refs_to->to_refs[n]]);
  1956.         switch(*fp) {
  1957.         case F_ROW:
  1958.         case F_COL:
  1959.             push_cell(cur_row,cur_col);
  1960.             break;
  1961.  
  1962.         case R_CELL:
  1963.         case R_CELL|ROWREL:
  1964.         case R_CELL|COLREL:
  1965.         case R_CELL|ROWREL|COLREL:
  1966.         {
  1967.             CELLREF trr,tcc;
  1968.             CELL *tcp;
  1969.  
  1970.             /* These are more difficult */
  1971.             trr=GET_ROW(fp+1);
  1972.             tcc=GET_COL(fp+1);
  1973.             tcp=find_cell(trr,tcc);
  1974. #ifdef TEST
  1975.             if(!tcp)
  1976.                 panic("Can't find_cell(%s) in shift_formula",cell_name(trr,tcc));
  1977. #endif
  1978.             flush_ref_fm(&(tcp->cell_refs_from),cur_row-dn,cur_col-ov);
  1979.  
  1980.             if(((*fp)&ROWREL) && dn) {
  1981.                 trr+=dn;
  1982.                 PUT_ROW(fp+1,trr);
  1983.             }
  1984.             if(((*fp)&COLREL) && ov) {
  1985.                 tcc+=ov;
  1986.                 PUT_COL(fp+1,tcc);
  1987.             }
  1988.             tcp=find_or_make_cell(trr,tcc);
  1989.             add_ref_fm(&(tcp->cell_refs_from),cur_row,cur_col);
  1990.         }
  1991.             break;
  1992.  
  1993.         case RANGE:
  1994.         case RANGE|LRREL:
  1995.         case RANGE|LRREL|LCREL:
  1996.         case RANGE|LRREL|LCREL|HCREL:
  1997.         case RANGE|LRREL|HCREL:
  1998.         case RANGE|LRREL|HRREL:
  1999.         case RANGE|LRREL|HRREL|LCREL:
  2000.         case RANGE|LRREL|HRREL|LCREL|HCREL:
  2001.         case RANGE|LRREL|HRREL|HCREL:
  2002.         case RANGE|HRREL:
  2003.         case RANGE|HRREL|LCREL:
  2004.         case RANGE|HRREL|LCREL|HCREL:
  2005.         case RANGE|HRREL|HCREL:
  2006.         case RANGE|LCREL:
  2007.         case RANGE|LCREL|HCREL:
  2008.         case RANGE|HCREL:
  2009.         {
  2010.             struct rng orng;
  2011.             GET_RNG(fp+1,&orng);
  2012.  
  2013.             flush_range_ref(&orng,cur_row-dn,cur_col-ov);
  2014.  
  2015.             if((*fp)&LRREL)
  2016.                 orng.lr+=dn;
  2017.             if((*fp)&HRREL)
  2018.                 orng.hr+=dn;
  2019.             if((*fp)&LCREL)
  2020.                 orng.lc+=ov;
  2021.             if((*fp)&HCREL)
  2022.                 orng.hc+=ov;
  2023.             PUT_RNG(fp+1,&orng);
  2024.             add_range_ref(&orng);
  2025.         }
  2026.             break;
  2027.  
  2028.         case VAR:
  2029.         {
  2030.             struct var *v;
  2031.             struct cell *tcp;
  2032.  
  2033.             bcopy(&fp[1],&v,sizeof(struct var *));
  2034.             flush_ref_fm(&(v->var_ref_fm),cur_row-dn,cur_col-ov);
  2035.             add_ref_fm(&(v->var_ref_fm),cur_row,cur_col);
  2036.             switch(v->var_flags) {
  2037.             case VAR_UNDEF:
  2038.                 break;
  2039.  
  2040.             case VAR_CELL:
  2041.                 tcp=find_cell(v->v_rng.lr,v->v_rng.lc);
  2042. #ifdef TEST
  2043.                 if(!tcp)
  2044.                     panic("Can't find_cell(%s) in shift_formula",cell_name(v->v_rng.lr,v->v_rng.lc));
  2045. #endif
  2046.                 flush_ref_fm(&(tcp->cell_refs_from),cur_row-dn,cur_col-ov);
  2047.                 add_ref_fm(&(tcp->cell_refs_from),cur_row,cur_col);
  2048.                 break;
  2049.  
  2050.             case VAR_RANGE:
  2051.                 flush_range_ref(&(v->v_rng),cur_row-dn,cur_col-ov);
  2052.                 add_range_ref(&(v->v_rng));
  2053.                 break;
  2054.  
  2055. #ifdef TEST
  2056.             default:
  2057.                 panic("Unknown var type %d",v->var_flags);
  2058. #endif
  2059.             }
  2060.         }
  2061.             break;
  2062.  
  2063.         default:
  2064.         {
  2065.             struct function *fun;
  2066.  
  2067.             if(*fp<USR1)
  2068.                 fun= &the_funs[*fp];
  2069. #ifdef TEST
  2070.             else if(*fp>=SKIP)
  2071.                 fun=0,panic("SKIP? in shift_formula?");
  2072. #endif
  2073.             else
  2074.                 fun= &usr_funs[*fp][fp[1]];
  2075.                 /* These are easy */
  2076.             if(fun->fn_comptype&C_T) {
  2077.                 flush_ref_fm(&timer_cells,cur_row-dn,cur_col-ov);
  2078.                 add_ref_fm(&timer_cells,cur_row,cur_col);
  2079.             }
  2080. #ifdef TEST
  2081.             else
  2082.                 panic("How do I deal with byte %d in shift_formula()?",*fp);
  2083. #endif
  2084.         }
  2085.             break;
  2086.             
  2087.         }
  2088.     }
  2089. }
  2090.  
  2091.  
  2092. /* ---------------- Routines for dealing with async functions -------------- */
  2093.  
  2094. #if defined(NO_UALARM)
  2095.  
  2096. #ifdef SETITIMER
  2097.  
  2098. #include <time.h>
  2099.  
  2100. unsigned ualarm FUN2(unsigned,first, unsigned,others)
  2101. {
  2102.     struct itimerval foo;
  2103.  
  2104.     foo.it_value.tv_sec =first/1000000;
  2105.     foo.it_value.tv_usec=first%1000000;
  2106.     foo.it_interval.tv_sec =others/1000000;
  2107.     foo.it_interval.tv_usec=others%1000000;
  2108.     setitimer(ITIMER_REAL, &foo, (struct itimerval *)0);
  2109.     return 0;
  2110. }
  2111. #else
  2112.  
  2113. static unsigned alarm_interval;
  2114.  
  2115. unsigned ualarm FUN2(unsigned,value, unsigned,interval)
  2116. {
  2117.     if(value==0 && interval==0)
  2118.         return alarm(0);
  2119.     alarm_interval=interval;
  2120.     return alarm(value);
  2121. }
  2122. #endif
  2123. #endif
  2124.  
  2125. /* This function is called when we get SIGALRM
  2126.    It just dumps timer_cells->fm_refs */
  2127. void
  2128. deal_alarm()
  2129. {
  2130.     int n;
  2131.  
  2132. #ifdef SYSV
  2133.     signal(SIGALRM, deal_alarm);
  2134. #endif
  2135. #if defined(NO_UALRM) && !defined(SETITIMER)
  2136.     alarm(alarm_interval);
  2137. #endif
  2138. #ifdef TEST
  2139.     if(!timer_cells || !timer_cells->refs_used)
  2140.         panic("No timer cells?");
  2141. #endif
  2142.     current_cycle++;
  2143.     for(n=0;n<timer_cells->refs_used;n++)
  2144.         push_cell(timer_cells->fm_refs[n].ref_row,timer_cells->fm_refs[n].ref_col);
  2145. }
  2146.  
  2147. /* All the timer_cells are going away, 'cuz everything is going away. . . */
  2148. void
  2149. flush_all_timers FUN0()
  2150. {
  2151.     if(timer_active) {
  2152. #ifdef SPLIT_REFS
  2153.         timer_cells->refs_used=0;
  2154. #else
  2155.         flush_fm_ref(timer_cells);
  2156.         timer_cells=0;
  2157. #endif
  2158.         timer_active=0;
  2159. #ifndef __TURBOC__
  2160.         ualarm(0,0);
  2161. #endif
  2162.     }
  2163. }
  2164.  
  2165. /* Add CUR_ROW, CUR_COL to the list of active timer-cells, turning on
  2166.    the timer_active, if it isn't already */
  2167. void
  2168. add_timer_ref FUN1(int,whereto)
  2169. {
  2170.     add_ref_to(whereto);
  2171.     add_ref_fm(&timer_cells,cur_row,cur_col);
  2172.     if(!timer_active) {
  2173.         timer_active++;
  2174. #ifndef __TURBOC__
  2175.         signal(SIGALRM,deal_alarm);
  2176.         ualarm(signal_ticks, signal_ticks);
  2177. #endif
  2178.     }
  2179. }
  2180.  
  2181. /* ---------- Routines and vars for dealing with the eval FIFO ------------ */
  2182. static struct cell_buf cell_buffer;
  2183.  
  2184. /* Start up the FIFO of cells to update */
  2185. void
  2186. init_refs FUN0()
  2187. {
  2188.     cell_buffer.size=FIFO_START;
  2189.     cell_buffer.buf=(struct pos *)ck_malloc(cell_buffer.size*sizeof(struct pos));
  2190.     bzero(cell_buffer.buf,cell_buffer.size*sizeof(struct pos));
  2191.     cell_buffer.push_to_here=cell_buffer.buf;
  2192.     cell_buffer.pop_frm_here=cell_buffer.buf;
  2193.     the_vars=hash_new();
  2194. }
  2195.  
  2196. /* Push the cells in REF onto the FIFO.  This calls push_cell to do the
  2197.    actual work. . . */
  2198. void
  2199. push_refs FUN1(struct ref_fm *, ref)
  2200. {
  2201.     int n;
  2202.  
  2203.     if(!ref || !ref->refs_used)
  2204.         return;
  2205.     n=ref->refs_used;
  2206.     while(n--) {
  2207. #ifdef TEST
  2208.         CELL *cp;
  2209.  
  2210.         if(debug&04)
  2211.             error_msg("Push %s",cell_name(ref->fm_refs[n].ref_row,ref->fm_refs[n].ref_col));
  2212.         cp=find_cell(ref->fm_refs[n].ref_row,ref->fm_refs[n].ref_col);
  2213.         if(cp->cell_cycle==current_cycle) {
  2214.             if(debug&01)
  2215.                 error_msg("Cycle detected from %s to %s",
  2216.                     cell_name(cur_row,cur_col),
  2217.                     cell_name(ref->fm_refs[n].ref_row,ref->fm_refs[n].ref_col));
  2218.             push_cell(ref->fm_refs[n].ref_row,
  2219.                   ref->fm_refs[n].ref_col);
  2220.         } else
  2221. #endif
  2222.         push_cell(ref->fm_refs[n].ref_row,ref->fm_refs[n].ref_col);
  2223.     }
  2224. }
  2225.  
  2226. /* Push a cell onto the FIFO of cells to evaluate, checking for cells
  2227.    that are already on the FIFO, etc.
  2228.  
  2229.    This does not implement best-order recalculation, since there may be
  2230.    intersecting branches in the dependency tree, however, it's close enough
  2231.    for most people.
  2232.  */
  2233. void
  2234. push_cell FUN2(CELLREF,row, CELLREF,col)
  2235. {
  2236.     struct pos *dup;
  2237.     CELL *cp;
  2238.     struct ref_fm *rf;
  2239.  
  2240.     if(cell_buffer.push_to_here+1==cell_buffer.pop_frm_here || (cell_buffer.pop_frm_here==cell_buffer.buf && cell_buffer.push_to_here==cell_buffer.buf+(cell_buffer.size-1))) {
  2241.         int f, t, from_num;
  2242.  
  2243.         f=cell_buffer.pop_frm_here-cell_buffer.buf;
  2244.         t=cell_buffer.push_to_here-cell_buffer.buf;
  2245.         from_num=cell_buffer.size-f;
  2246.  
  2247.         cell_buffer.size FIFO_INC;
  2248.  
  2249.         cell_buffer.buf=(struct pos *)ck_realloc((VOIDSTAR )cell_buffer.buf,cell_buffer.size*sizeof(struct pos));
  2250.         if(t==0) {
  2251.             cell_buffer.push_to_here=cell_buffer.buf+f+from_num;
  2252.             cell_buffer.pop_frm_here=cell_buffer.buf+f;
  2253.         } else if(t>f) {
  2254.             cell_buffer.push_to_here=cell_buffer.buf+t;
  2255.             cell_buffer.pop_frm_here=cell_buffer.buf+f;
  2256.         } else {
  2257.             cell_buffer.push_to_here=cell_buffer.buf+t;
  2258.             cell_buffer.pop_frm_here=cell_buffer.buf+(cell_buffer.size-from_num);
  2259.             if(from_num)
  2260.                 bcopy(    cell_buffer.buf+f,
  2261.                     cell_buffer.pop_frm_here,
  2262.                     from_num*sizeof(struct pos));
  2263.         }
  2264.     }
  2265.  
  2266. #if 1
  2267.     if(cell_buffer.pop_frm_here!=cell_buffer.push_to_here) {
  2268.         dup=cell_buffer.pop_frm_here;
  2269.  
  2270.         cp=find_cell(row,col);
  2271.         if(!cp) {
  2272.             return;
  2273.         }
  2274.         rf=cp->cell_refs_from;
  2275.         for(;dup!=cell_buffer.push_to_here;) {
  2276.             if(dup->row==row && dup->col==col) {
  2277. #ifdef TEST
  2278.                 if(debug&010)
  2279.                     error_msg("Flushed dup ref to %s",cell_name(row,col));
  2280. #endif
  2281.                 *dup= *(cell_buffer.pop_frm_here);
  2282.                 cell_buffer.pop_frm_here++;
  2283.                 if(cell_buffer.pop_frm_here==cell_buffer.buf+cell_buffer.size)
  2284.                     cell_buffer.pop_frm_here=cell_buffer.buf;
  2285.                 break;
  2286.             }
  2287. #if 0
  2288.             if(rf) {
  2289.                 for(n=0;n<rf->refs_used;n++)
  2290.                     if(rf->fm_refs[n].ref_row==dup->row && rf->fm_refs[n].ref_col==dup->col) {
  2291. #ifdef TEST
  2292.                         if(debug&01)
  2293.                             error_msg("Swapped %s and %s",cell_name(row,col),cell_name(dup->row,dup->col));
  2294. #endif
  2295.                         dup->row=row;
  2296.                         dup->col=col;
  2297.                         row=rf->fm_refs[n].ref_row;
  2298.                         col-rf->fm_refs[n].ref_col;
  2299.                         goto breakout;
  2300.                     }
  2301.             }
  2302. #endif
  2303.  
  2304.             if(++dup==cell_buffer.buf+cell_buffer.size)
  2305.                 dup=cell_buffer.buf;
  2306.         }
  2307.     }
  2308. #endif
  2309.  
  2310.     cell_buffer.push_to_here->row=row;
  2311.     cell_buffer.push_to_here->col=col;
  2312.     cell_buffer.push_to_here++;
  2313.     if(cell_buffer.push_to_here==cell_buffer.buf+cell_buffer.size)
  2314.         cell_buffer.push_to_here=cell_buffer.buf;
  2315. }
  2316.  
  2317. /* Pop a cell off CELL_BUFFER, and evaluate it, displaying the result. . .
  2318.    This returns 0 if there are no more cells to update, or if it gets
  2319.    an error. */
  2320.  
  2321. int
  2322. eval_next_cell FUN0()
  2323. {
  2324.     CELL *cp;
  2325.     static loop_counter = 40;
  2326.  
  2327.     if(cell_buffer.pop_frm_here==cell_buffer.push_to_here)
  2328.         return 0;
  2329. #ifdef TEST
  2330.     if(cell_buffer.pop_frm_here->row==NON_ROW || cell_buffer.pop_frm_here->col==NON_COL) {
  2331.         error_msg("Popping NON_CELL in eval_next_cell");
  2332.         return 0;
  2333.     }
  2334. #endif
  2335.  
  2336.     cur_row=cell_buffer.pop_frm_here->row;
  2337.     cur_col=cell_buffer.pop_frm_here->col;
  2338.     cell_buffer.pop_frm_here++;
  2339.     if(cell_buffer.pop_frm_here==cell_buffer.buf+cell_buffer.size)
  2340.         cell_buffer.pop_frm_here=cell_buffer.buf;
  2341.  
  2342.     cp=find_cell(cur_row,cur_col);
  2343.     if(cp) {
  2344.         if(cp->cell_cycle==current_cycle)
  2345.             --loop_counter;
  2346.         else
  2347.             loop_counter=40;
  2348.         update_cell(cp);
  2349.         pr_cell(cur_row,cur_col,cp);
  2350.         return loop_counter;
  2351.     } else {
  2352. #ifdef TEST
  2353.         error_msg("Can't update cell %s doesn't exist",cell_name(cur_row,cur_col));
  2354. #endif
  2355.         return 0;
  2356.     }
  2357. }
  2358.  
  2359. #ifdef TEST
  2360. void
  2361. cell_buffer_contents FUN0()
  2362. {
  2363.     struct pos *ptr;
  2364.  
  2365.     if(cell_buffer.pop_frm_here!=cell_buffer.push_to_here) {
  2366.         ptr=cell_buffer.pop_frm_here;
  2367.         for(;;) {
  2368.             printf("Ref to %s\r\n",cell_name(ptr->row,ptr->col));
  2369.             if(++ptr==cell_buffer.buf+cell_buffer.size)
  2370.                 ptr=cell_buffer.buf;
  2371.             if(ptr==cell_buffer.push_to_here)
  2372.                 break;
  2373.         }
  2374.     }
  2375.     printf("End of buffer\r\n");
  2376. }
  2377. #endif
  2378.  
  2379. /* ----------------- Routines for dealing with variables ------------------ */
  2380.  
  2381. /* This sets the variable V_NAME to V_NEWVAL
  2382.    It returns error msg, or 0 on success.
  2383.    All the appropriate cells have their ref_fm arrays adjusted appropriatly
  2384.    This could be smarter; when changing a range var, only the cells that
  2385.    were in the old value but not in the new one need their references flushed,
  2386.    and only the cells that are new need references added.
  2387.    This might also be changed to use add_range_ref()?
  2388.  */
  2389. char *
  2390. new_var_value FUN3(char *, v_name, int, v_namelen, char *,v_newval)
  2391. {
  2392.     struct var *var;
  2393.     int n;
  2394.     int newflag;
  2395.     struct rng tmp_rng;
  2396.  
  2397.     cur_row=MIN_ROW;
  2398.     cur_col=MIN_COL;
  2399.     if(v_newval && *v_newval) {
  2400.         n=parse_cell_or_range(&v_newval,&tmp_rng);
  2401.         if(!n)
  2402.             return "Can't parse cell or range";
  2403.         if(*v_newval)
  2404.             return "Junk after cell or range";
  2405.         newflag=((n|ROWREL|COLREL)==(R_CELL|ROWREL|COLREL)) ? VAR_CELL : VAR_RANGE;
  2406.     } else {
  2407.         tmp_rng.lr=tmp_rng.hr=NON_ROW;
  2408.         tmp_rng.lc=tmp_rng.hc=NON_COL;
  2409.         newflag= VAR_UNDEF;
  2410.     }
  2411.  
  2412.     var=find_or_make_var(v_name,v_namelen);
  2413.  
  2414.     if(var->var_ref_fm) {
  2415.         if(var->var_flags!=VAR_UNDEF) {
  2416.             for(n=0;n<var->var_ref_fm->refs_used;n++) {
  2417.                 flush_range_ref(&(var->v_rng),
  2418.                     var->var_ref_fm->fm_refs[n].ref_row,
  2419.                     var->var_ref_fm->fm_refs[n].ref_col);
  2420.             }
  2421.         }
  2422.         var->v_rng = tmp_rng;
  2423.  
  2424.         if(var->v_rng.lr!=NON_ROW) {
  2425.             for(n=0;n<var->var_ref_fm->refs_used;n++) {
  2426.                 cur_row=var->var_ref_fm->fm_refs[n].ref_row;
  2427.                 cur_col=var->var_ref_fm->fm_refs[n].ref_col;
  2428.                 add_range_ref(&(var->v_rng));
  2429.             }
  2430.         }
  2431.         for(n=0;n<var->var_ref_fm->refs_used;n++)
  2432.             push_cell(var->var_ref_fm->fm_refs[n].ref_row,
  2433.                 var->var_ref_fm->fm_refs[n].ref_col);
  2434.     } else
  2435.         var->v_rng = tmp_rng;
  2436.  
  2437.     var->var_flags=newflag;
  2438.  
  2439.     return 0;
  2440. }
  2441.  
  2442. void
  2443. #ifdef __STDC__
  2444. for_all_vars(void (*func)())
  2445. #else
  2446. for_all_vars(func)
  2447. void (*func)();
  2448. #endif
  2449. {
  2450.     hash_apply(the_vars,func);
  2451. }
  2452.  
  2453. /* Find a variable in the list of variables, or create it if it doesn't
  2454.    exist.  Takes a name and a length so the name doesn't have to be
  2455.    null-terminated
  2456.  */
  2457. struct var *
  2458. find_or_make_var FUN2(char *, string, int, len)
  2459. {
  2460.     struct var *ret;
  2461.     int ch;
  2462.  
  2463.     ch=string[len];
  2464.     string[len]='\0';
  2465.  
  2466.     ret=hash_find(the_vars,string);
  2467.     if(ret) {
  2468.         string[len]=ch;
  2469.         return ret;
  2470.     }
  2471.  
  2472.     ret=(struct var *)ck_malloc(sizeof(struct var)+len);
  2473.     bcopy(string,ret->var_name,len+1);
  2474.     ret->var_flags=VAR_UNDEF;
  2475.     ret->v_rng.lr=0;
  2476.     ret->v_rng.lc=0;
  2477.     ret->v_rng.hr=0;
  2478.     ret->v_rng.hc=0;
  2479.     ret->var_ref_fm=0;
  2480.     hash_insert(the_vars,ret->var_name,ret);
  2481.     string[len]=ch;
  2482.     return ret;
  2483. }
  2484.  
  2485. /* Like find-or-make-var except returns 0 if it doesn't exist */
  2486. struct var *
  2487. find_var FUN2(char *, string, int, len)
  2488. {
  2489.     int ch;
  2490.     struct var *ret;
  2491.  
  2492.     ch=string[len];
  2493.     string[len]='\0';
  2494.     ret=hash_find(the_vars,string);
  2495.     string[len]=ch;
  2496.     return ret;
  2497. }
  2498.  
  2499. /* This adds a reference from CUR_ROW,CUR_COL to the variable VAR
  2500.    It calls add_ref or add_range_ref to have the cell(s) in VAR be
  2501.    referenced by CUR_ROW,CUR_COL
  2502.  */
  2503. void
  2504. add_var_ref FUN1(struct var *, var)
  2505. {
  2506.     add_ref_fm(&(var->var_ref_fm),cur_row, cur_col);
  2507.     switch(var->var_flags) {
  2508.     case VAR_UNDEF:
  2509.         break;
  2510.     case VAR_CELL:
  2511.         add_ref(var->v_rng.lr, var->v_rng.lc);
  2512.         break;
  2513.     case VAR_RANGE:
  2514.         add_range_ref(&(var->v_rng));
  2515.         break;
  2516. #ifdef TEST
  2517.     default:
  2518.         panic("Unknown var type %d in add_var_ref",var->var_flags);
  2519. #endif
  2520.     }
  2521. }
  2522.  
  2523. static void
  2524. flush_var FUN2(char *,name, struct var *,var)
  2525. {
  2526. #ifdef SPLIT_REFS
  2527.     if(var->var_ref_fm)
  2528.         free(var->var_ref_fm);
  2529. #endif
  2530.     free(var);
  2531. }
  2532.  
  2533.  
  2534. /* Free up all the variables, and (if SPLIT_REFS) the ref_fm structure
  2535.    associated with each variable.  Note that this does not get rid of
  2536.    the struct var *s in cell expressions, so it can only be used when all
  2537.    the cells are being freed also
  2538.  */
  2539. void
  2540. flush_variables FUN0()
  2541. {
  2542.     for_all_vars(flush_var);
  2543.     hash_die(the_vars);
  2544.     the_vars=hash_new();
  2545. }
  2546.  
  2547.